|
From: James Giles on 21 Jan 2008 14:58 James Van Buskirk wrote: .... > [,,,] You know, a compiler could return .TRUE. for > > logical function is_broken() > is_broken=transfer(transfer(2,.TRUE.).NEQV.transfer(4,.TRUE.),0)==1 > end > > and one could argue forever about whether that is reasonable > behavior, but it would not mean that the compiler was usable. It wouldn't mean the compiler was UNusable either. It's not at all difficult to contrive a possible case. Suppose you have a platform with instructions that XOR (the actual operation of .NEQV.) whole words of the operands or, faster, just an individual byte of the operands. Suppose further that the Fortran implementor chose to use the leading bit (the sign, if the data is interpreted as an INTEGER) as the significant bit as far as LOGICAL goes. It would not be at all surprising for the implementation to choose to XOR only the leading byte of the operands and store only that leading byte into the result location (register or memory) - it's faster. Well, that means contents of the operand values below the top byte are not relevant or even referenced. It means that the contents of the result value below the top byte will remain whatever was there before the .NEQV. result was stored there - it's all irrelevant anyway. It could be the value one (1). Who cares? Hey maybe the implementor chose to guarantee by some means that all LOGICAL results have odd parity regardless of their value. There are two aspects to this question. The first is that TRANSFER portably guarantees only one thing: If (and only if) type2 is at least as large as type1, TRANSFER from type1 to type2 and back again is guaranteed to yield that same value as you started with. If you do any operations on the data as a type2 entity all bets are off (this includes assignment, since the implementation is free to "normalize" during assignment). Beyond that one guarantee, the use of TRANSFER is entirely implementation dependent. To assume that ANY property of those implementation dependent things is portably reliable is not justified. The second aspect of this issue is that I've never seen, and can't even imagine, any case where I would want to TRANSFER between LOGICAL and anything else. At least, not any cases where I would do any operations on the intermediate results of such a transfer. Sure, if I wanted a heterogenous array I might transfer a logical value into what the compiler considers an integer array element. But in that case I'd remember what that element really was and *never* use it as an integer. -- J. Giles "I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies." -- C. A. R. Hoare
From: James Van Buskirk on 21 Jan 2008 16:11 "James Giles" <jamesgiles(a)worldnet.att.net> wrote in message news:pP6lj.469042$kj1.58346(a)bgtnsc04-news.ops.worldnet.att.net... > The second aspect of this issue is that I've never seen, and can't > even imagine, any case where I would want to TRANSFER between > LOGICAL and anything else. At least, not any cases where I would > do any operations on the intermediate results of such a transfer. > Sure, if I wanted a heterogenous array I might transfer a logical > value into what the compiler considers an integer array element. > But in that case I'd remember what that element really was and > *never* use it as an integer. I guess you've not done much C interop, then. If you check out N1601.pdf, table 15.2, LOGICAL(C_BOOL) is considered interoperable with C type _Bool which may just mean int. Suppose you are given a *.mod file which contains interfaces to C functions. You may not be able to recompile it so you may have to follow the choices made by the programmer who compiled that *.mod file. Such a programmer could quite easily have typed dummy arguments as LOGICAL(C_BOOL). Since you have to send a LOGICAL actual argument, but there is no way of guaranteeing that .TRUE. and .FALSE. correspond to C99 true and false which are defined as 1 and 0, you would have to use actual arguments of TRANSFER(1,.TRUE.) and TRANSFER(0,.FALSE.). Similarly if a function result were LOGICAL(C_BOOL) we would need to use TRANSFER once again to convert to an integer which could be tested for its zero or nonzero properties. Instead of if(f(x)) then .... we would need to write if(TRANSFER(f(x),0) /= 0) then .... ISTR that I have seen some Win32 API *.mod files where you had to do this, but looking at kernel32.f90 from the ifort distribution, everything is typed as INTEGER(BOOL) so the TRANSFERs aren't necessary. Perhaps my recollection is wrong on this point. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
From: James Giles on 21 Jan 2008 16:36 James Van Buskirk wrote: .... > I guess you've not done much C interop, then. If you check out > N1601.pdf, table 15.2, LOGICAL(C_BOOL) is considered interoperable > with C type _Bool which may just mean int. [...] And that's relevant to what I said how? LOGICAL(B_BOOL) isn't (as your last example supposed) a *default* LOGICAL KIND. At least it isn't necessarily so. > [...] Suppose you are given > a *.mod file which contains interfaces to C functions. You may not > be able to recompile it so you may have to follow the choices made > by the programmer who compiled that *.mod file. Such a programmer > could quite easily have typed dummy arguments as LOGICAL(C_BOOL). > Since you have to send a LOGICAL actual argument, but there is no > way of guaranteeing that .TRUE. and .FALSE. correspond to C99 true > and false which are defined as 1 and 0, you would have to use > actual arguments of TRANSFER(1,.TRUE.) and TRANSFER(0,.FALSE.). No, you have to use TRUE._C_BOOL and .FALSE._C_BOOL. > Similarly if a function result were LOGICAL(C_BOOL) we would > need to use TRANSFER once again to convert to an integer which > could be tested for its zero or nonzero properties. Instead of > > if(f(x)) then > ... > > we would need to write > > if(TRANSFER(f(x),0) /= 0) then The function f(x) has an interface does it not? That interface declared the return type as LOGICAL(C_BOOL) did it not? You shouldn't need TRANSFER at all. IF(F(X)) then ... should work just fine. Complain to your vendor if it gets something that simple so very wrong. Yes, because of the fact that the C standard makes specific requirements on booleans, the KIND C_BOOL of LOGICAL can be relied to portably have those properties. The Fortran companion processor should get those right without the need for TRANSFER. -- J. Giles "I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies." -- C. A. R. Hoare
From: James Van Buskirk on 22 Jan 2008 01:50 "James Giles" <jamesgiles(a)worldnet.att.net> wrote in message news:wf8lj.469433$kj1.393176(a)bgtnsc04-news.ops.worldnet.att.net... > The function f(x) has an interface does it not? That interface declared > the return type as LOGICAL(C_BOOL) did it not? You shouldn't need > TRANSFER at all. IF(F(X)) then ... should work just fine. Complain > to your vendor if it gets something that simple so very wrong. > Yes, because of the fact that the C standard makes specific requirements > on booleans, the KIND C_BOOL of LOGICAL can be relied to portably > have those properties. The Fortran companion processor should get those > right without the need for TRANSFER. Oog. Looking at the C99 standard, I see that _Bool, although it's an integer type, has semantics distinct from int. In particular, when conversion to _Bool is required any mumeric value that isn't zero gets converted to 1 (didn't carefully check what happens to imaginary values, though) and the example given in the standard is that (int)0.5 = 0, but (_Bool)0.5 = 1 . That means that I have introduced a red herring into my own argument in that LOGICAL(C_BOOL) is to preexisting Fortran LOGICAL kinds what IEEE-754 data types are to, say, VAX floating types like G_FLOAT. G_FLOAT has different internal representation from IEEE-754 double precision (T_FLOAT), but it is still a floating point data type and operations between T_FLOATs should yield predictable T_FLOAT values while operations between G_FLOATs should yield predictable G_FLOAT values and operations between a G_FLOAT and a T_FLOAT should convert one of the inputs to the kind of the other before computing a result. Similar rules would be expected for preexisting LOGICAL kinds and LOGICAL(C_BOOL). Just as implementing IEEE-754 is optional, implementing LOGICAL(C_BOOL) is optional, and would have different internal representation from other kinds. In particular, transfer(.NOT.transfer(1,.TRUE._C_BOOL),0) would have to come out 0, whereas the more normal result (due to the use of masking expressions pre-MIL-STD 1753) would be -2 . The big difference is the conversion of true values to 1 for a C99 _Bool which doesn't happen for C ints. What I was thinking about was for pre-C99 where _Bool might get defined as int, but this is not the case covered by f03 and LOGICAL(C_BOOL). So I am back to discussing interoperability with pre-99 C where you really could get passed values with internal representations identical to those of 2 or 4 . I wanted to find an instance of that in Win32 API modules included with Fortran compilers, but in at least the more recent versions of CVF, BOOL is properly typed an INTEGER(BOOL). In LF95 there is a file call win32mod.mod and if you USE win32mod you get type definitions and interfaces to Win32 API functions but I couldn't find any documentation about the module and if you don't correctly guess the type LF95 chose for a dummy argument it prints an error statement that doesn't tell you which one it didn't like, so I don't know how to get enough working so that I could tell whether LF95 is using LOGICAL or INTEGER types to represent Win32 API BOOL. And I was going to write up an example where a C function passed values of 2 and 4 to a Fortran callback function which took them to be LOGICAL and then preformed the .NEQV. binary operation between them and passed the result back to the C function and caused some undesirable action if the result were 1 , but I'm just too tired so I will have to leave it as an exercise for the reader. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
|
Pages: 1 Prev: FITS Library Package upgrade Next: gfortran -std=f95 overzealous? |