Integers as logical operators?

Integers as logical operators?

I know in C, integers used as logical expressions evaluate anything != 0 as TRUE, and 0 as FALSE.  I had assumed (or maybe I was dreaming) that Fortran did the same.  I always tell people never to pass a Fortran logical to a C function and expect the value to be 0 or 1, because in my experience it is usually a random number or 0.

 

HOWEVER, I'm seeing something now that is a bit perplexing.  I have a local INTEGER*4 variable that I set to the result of a bitwise expression:

I = IAND( UPDATE_CLASS, 512 )
IF ( I ) THEN
  WRITE( *, * ) 'I WAS TRUE'
END IF

When UPDATE_CLASS is 512, I never get the printout.  Upon examining the generated assembler, we have:

% I = IAND( UPDATE_CLASS, 512 )
mov eax, dword ptr [0x111111]
and eax, 0x200
mov dword ptr [0x123123], eax
% IF ( I ) THEN
test al, 0x1
jz 0x7543212

....so, if my assembler interpretation is correct, it looks like it's only checking to see if the first bit of the integer value is set, not any bit.  Is this expected behavior?  I tried asking The Google, but I can't seem to find any documentation on treating integers as logical expressions.

Thanks

11 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

In the past, Fortran did not specify the internal representation of the LOGICAL type. See Doctor Fortran in "To .EQV. or to .NEQV., that is the question", or "It's only LOGICAL" for some background. Intel Fortran's default is derived from that of DEC Fortran, which used the low bit only and ignored the rest.

Fortran 2003, as an inference from the C interoperability features, says that the C _Bool type is interoperable with Fortran LOGICAL, which means it should use the zero/not-zero test instead. We provide that if you specify the option "-fpscomp logicals" or "-standard-semantics".

It is still nonconforming to use LOGICALs where a numeric type is required, and vice-versa. What you're doing is not standard Fortran.

Retired 12/31/2016

Ah, thanks.  Is there a way to get the compiler to emit a warning when an INTEGER data type is used as a logical expression to be able to find these instances more easily?

Quote:

ereisch wrote:

Ah, thanks.  Is there a way to get the compiler to emit a warning when an INTEGER data type is used as a logical expression to be able to find these instances more easily?

+1 for this feature request if it’s not implemented yet, and finding .eq. with logical instead of .eqv. would be super too.

The documentation I find says -fpscomp logicals sets values of 0 or 1, so either the zero/non-zero or even/odd testing should work for logical data types.  Prior to f2003, as Steve said, Fortran had no such C binary compatibility requirement.  The reason for doing it is not to support special behaviors in Fortran, only to assure that the  C_bool works on the C side.

Without fpscomp logicals, one might expect .true. to set a binary pattern the same as integer value -1, but code which depends on that is clearly non-portable, without a compelling reason to be that way.

The old DEC VAX style extension of testing integer data types for even/odd by ignoring the distinction from logical data type has been contrary to Fortran standard all along, but ifort doesn't warn about it unless -stand option is set  If you actually want that, you can make it explicit and standard compliant by e.g. if(iand(i,1) /= 0)..... without any penalty in performance of generated code (or you can test any bit of your choice)

The Fortran standard didn't require that C's _Bool type is compatible with any KIND of Fortran LOGICAL variables.  The Fortran processor is allowed to set C_BOOL = -1 and have the programmer test for .TRUE./.FALSE. according to the specifications of the companion C processor (if one exists) rather than turn itself inside out to match the C processor.  Even if C_BOOL /= -1, the Fortran processor could create a new LOGICAL KIND for compatibility with C _Bool, kind of like a new REAL KIND for decimal floats, that is not binary compatible with binary floats, or D_FLOAT/G_FLOAT/T_FLOAT.  Or the C processor could document its _Bool type to be compatible with LOGICAL(KIND=1), considering the high bits to not contribute to the value.  Destroying compatibility with existing legacy Fortran code seems not to have been forced by the F2003 standard, but rather was a choice made by compiler developers.

Apparently, the Intel team found the fpscomp logicals option (compatibility with extinct Microsoft Fortran) suitable to support logical(c_bool).  In my mind, fpscomp is a sort of legacy option also.  The choice of c_bool as a single byte logical kind seems to be a usual one among other Fortran compilers.

As far as I know, it's still perfectly normal to use C_int data types for true and false values on the C side, but 32-bit logical data types appear in ifort iso_c_binding.f90 only inside interface c_f_procpointer.  So I don't see accepted portable practice for interoperability of 32- or 64-bit logical data types.  I'm not happy about relying on a legacy ifort feature which violates Fortran standard and isn't accepted by other Fortrans.  I found a reference to use of the IBM XL Fortran qport=clogicals option (apparently resembling ifort fpscomp logicals) with bigger logical data types, where it is admitted this doesn't fully support the goals of C interop.

https://www.ibm.com/developerworks/community/blogs/b10932b4-0edd-4e61-89...

 

-std will detect use of LOGICALs as numeric and vice-versa. Tim is correct that such mixing is nonstandard, but it seemed so reasonable at the time (and convenient with the design of VMS condition values.)

Repeat Offender is, technically, correct in that an implementation is allowed to say that there is no LOGICAL kind corresponding to _Bool. But that would be a choice most users would find unacceptable. I'm rather annoyed that the standards committee put this into the standard - I wasn't on the committee then.

Retired 12/31/2016

Quote:

Izaak Beekman wrote:

Quote:

ereisch wrote:

Ah, thanks.  Is there a way to get the compiler to emit a warning when an INTEGER data type is used as a logical expression to be able to find these instances more easily?

 

+1 for this feature request if it’s not implemented yet, and finding .eq. with logical instead of .eqv. would be super too.

I never really try -std (will now) but recent work I've been doing trying to get our weather model to compile with gfortran rather than our standard Intel (for portability, not performance) says gfortran (4.9.1) will tell you this. Indeed, it won't compile with statements like if(integer) or allow if (logical .eq. other_logical). We've really had to be more Standards standard getting our code to run with it.

LOGICAL FUNCTION C_BOOL(cb)
  INTEGER :: cb
  C_BOOL = (cb .ne. 0)
END FUNCTION C_BOOL

...

IF(C_BOOL(YourCBool)) THEN ...

Jim Dempsey

Quote:

thematt wrote:

Quote:

I never really try -std (will now) but recent work I've been doing trying to get our weather model to compile with gfortran rather than our standard Intel (for portability, not performance) says gfortran (4.9.1) will tell you this. Indeed, it won't compile with statements like if(integer) or allow if (logical .eq. other_logical). We've really had to be more Standards standard getting our code to run with it.

Yes, running your code past different compilers is always nice to help ensure that you’re not doing anything dicey. With gfortran I turn on -Wall -Wextra -pedantic -fbacktrace -stand=f2008 (or 95, 2003 etc.) while compiling and address or silence the warnings one by one. These extra checks have no, or minimal performance or size impact on the code produced by the compiler. For intel I use -W -traceback -std08, and then use -diag-disable to turn off errant warnings one by one, which is a really nice feature of the Intel compiler.

Leave a Comment

Please sign in to add a comment. Not a member? Join today