[comp.lang.fortran] extensions to logical variables

keith@stellar.UUCP (Keith Crews @stellar) (04/26/89)

I have some questions about common fortran extensions to logical variables.
Some fortrans (such as vms) have extended logicals so that they behave a lot
like integers in most contexts.  For example, you can assign them values
other than 0 and -1 (or whatever the conventional values for false and true
are) and you can do arithmetic on them.  However if you have assigned
values to them other than 0 or -1 you then get some strange results.
You get logical variables that are neither true nor false (kind of like
ieee nans) and you can have 2 non-zero logicals variables that don't have
the same truth value.  

The basic problem I have with the vax implementation is that I think that 
a logical variable should always be true or false.  You can do this by 
forcing a conversion to 0 or -1 when assigning to them (although this can 
be defeated by using equivalences) or you can treat all non-zero logicals 
as being true and only 0 as being false.  However, the vax and other compilers 
seem to have extended logicals by allowing them to act like integers in 
many contexts while leaving the underlying implementation alone and the 
result is that using extensions to logicals can result in some surprising 
results.

My questions are:  
    1)  Do people depend on having logicals that are neither true nor false?  
    2)  What would people consider a consistent set of semantic rules for 
these extensions to logicals?  
    3)  Should .eq. and .eqv. behave identically with logical operands 
or should .eq. do integer comparisons and .eqv. check for both zero or 
both non-zero?

If you allow 2 distinct non-zero logicals to not be equal (.eq. different from
.eqv. in 3 above) then you have another problem where the 2 expressions below 
may evaluate differently:

	l1 = 3
	l2 = .true.
	if (l1 .eq. .true.) ...
	if (l1 .eq. l2) ...

However, if you evaluate them the same then you are incompatible with vms
fortran which seems like a dubious idea.

I guess the real issue is whether I have missed a unifying idea under-
lying the vms implementation.

Here are a couple of examples:

This prints 0 on the vax:

	logical l1
	l1 = 3
	i = 0
	if (l1 .eq. .true.) then
	    i = 1
	endif
	if (l1 .eq. .false.) then
	    i = 2
	endif
	print *, i
	end

This prints 2 on the vax and 1 on the sun:

	logical l1, l2
	l1 = 3
	l2 = 4
	i = 0
	if (l1 .eqv. l2) then
	    i = 1
	endif
	if (l1 .neqv. l2) then
	    i = i + 2
	endif
	print *,i
	end
-- 
Keith Crews			Stellar Computer Inc.
				95 Wells Avenue, Newton, MA 02159

mikel@pyramid.pyramid.com (Mike Lipsie) (04/27/89)

In article <31660@stellar.UUCP> keith@stellar.UUCP (Keith Crews @stellar) writes:
>I have some questions about common fortran extensions to logical variables.
>
>The basic problem I have with the vax implementation is that I think that 
>a logical variable should always be true or false.  You can do this by 
>forcing a conversion to 0 or -1 when assigning to them (although this can 
>be defeated by using equivalences) or you can treat all non-zero logicals 
>as being true and only 0 as being false.  

Not answering Keith's question but rather pointing out an erroneous
assumption.  People who come from the C world seem to have internalized
false-true as zero-nonzero; those from Pascal as zero-one.  Other
implementations are possible.  A relatively common method is even-odd
because some machines had a fast low-order bit test; likewise, there
is positive-negative because of a fast sign bit test.

-- 
-----------
Mike Lipsie                                         mikel@pyramid.com
Pyramid Technology Corp, Mountain View, CA  +1 415 965 7200 ext. 4980

calvin@dinkum.SGI.COM (Calvin H. Vu) (04/28/89)

In article <31660@stellar.UUCP>, keith@stellar.UUCP (Keith Crews @stellar) writes:
> The basic problem I have with the vax implementation is that I think that 
> a logical variable should always be true or false.  You can do this by 
> forcing a conversion to 0 or -1 when assigning to them
	This is what ANSI says and that's what most non-VMS people expect,
	but some people do want logicals to retains its integer value after
	the assignment so they can be used in the same way as integers :-(.
	Don't search me for the answer though.   The only advantage in using
	extended logicals over integers, as far as I can see,  is that they 
	can do:
		logic = 3
		IF (logic) ...
	instead of:
		int = 3
		IF (and(int,1))
	since TRUE/FALSE condition on the VAX is evaluated by examining the
	last bit.

>     1)  Do people depend on having logicals that are neither true nor false?  
	Apparently so.   But I surely hope that they are the last of a
	dying breed :-}.   Nitpicking: they are neither .TRUE. nor .FALSE. 
	but they do evaluate to true or false according to their own 
	odd/eeven rule.

>     2)  What would people consider a consistent set of semantic rules for 
> these extensions to logicals?  
	Implementational expectation for exact compatibility:
	Allow extended logicals have the same values as integers and evaluate
	conditional expression by testing the last bit of the result. 

	For archaic processors which test TRUE/FALSE by looking at the 
	last bit this is no problem.  Nowaday, with the new processors 
	which test for zero/non-zero value, I doubt if anybody would do 
	an extra bit mask for each conditional expression evaluation just 
	to allow this ridiculous extension.   "How about my benchmarks ?",
	they'll say.

>     3)  Should .eq. and .eqv. behave identically with logical operands 
> or should .eq. do integer comparisons and .eqv. check for both zero or 
> both non-zero?
	.eq. is always implemented as integer comparison.   I don't know
	how .eqv. is implemented on VMS.   It would be interesting to test 
	if l1=1 and l2=3 are .eqv. on VMS.

> If you allow 2 distinct non-zero logicals to not be equal (.eq. different from
> .eqv. in 3 above) then you have another problem where the 2 expressions below 
> may evaluate differently:
> 
> 	l1 = 3
> 	l2 = .true.
> 	if (l1 .eq. .true.) ...
> 	if (l1 .eq. l2) ...
> 
> However, if you evaluate them the same then you are incompatible with vms
> fortran which seems like a dubious idea.
> 
> I guess the real issue is whether I have missed a unifying idea under-
> lying the vms implementation.
	The key is that VMS uses the odd/even concept of TRUE/FALSE so they
	can be liberal in the values their extended logical contains (i.e.
	all integer values).
> 
> Here are a couple of examples:
> 
> This prints 0 on the vax:
> 
> 	logical l1
> 	l1 = 3
> 	i = 0
> 	if (l1 .eq. .true.) then
> 	    i = 1
> 	endif
> 	if (l1 .eq. .false.) then
> 	    i = 2
> 	endif
> 	print *, i
> 	end
	.eq uses integer comparison so 3 is not equal to .TRUE. (which is 
	either 1 or -1)
> 
> This prints 2 on the vax and 1 on the sun:
> 
> 	logical l1, l2
> 	l1 = 3
> 	l2 = 4
> 	i = 0
> 	if (l1 .eqv. l2) then
> 	    i = 1
> 	endif
> 	if (l1 .neqv. l2) then
> 	    i = i + 2
> 	endif
> 	print *,i
> 	end
	SUN forces the logical values to either .TRUE. or .FALSE. so l1
	and l2 are both .TRUE. whereas on the VAX an odd 3 is not equivalent
	to an even 4 no matter how you look at it.
> -- 
> Keith Crews			Stellar Computer Inc.
> 				95 Wells Avenue, Newton, MA 02159

Calvin Vu

maine@drynix.dfrf.nasa.gov (04/28/89)

In article <31660@stellar.UUCP>, keith@stellar.UUCP (Keith Crews @stellar)
asks about the usage of logical variables as integers, particularly on
VAXen.

In article <31555@sgi.SGI.COM> calvin@dinkum.SGI.COM (Calvin H. Vu) writes:
> This is what ANSI says and that's what most non-VMS people expect,
> but some people do want logicals to retains its integer value after
> the assignment so they can be used in the same way as integers :-(.
> Don't search me for the answer though.   The only advantage in using
> extended logicals over integers, as far as I can see,  is that they 
> can do: ...

While acknowledging that this is all non-standard and non-portable and
thus to be avoided unless there are good arguments otherwise, there is
one usage of this construct that occasionally does seem justifiable.
(I've even done it myself in one case, while arguing with myself over
whether it was really the best approach).

The VAX allows a logical*1, which can be used as an unsigned (I think)
8-bit integer.  Oddly, the VAX does not recognize an integer*1 declaration,
so if you want an 8-bit integer, you need to use logical*1 instead.  You
don't really care how .TRUE. and .FALSE. are represented because you
are never really using these quantities as logicals.

Declaring something logical so you can use it as an integer is
confusing as well as non-standard, but if you really want an 8-bit
integer, what's a guy to do?  My "favorite" system, the Elxsi, allows
an integer*1 type (signed), which is admitedly still non-standard, but
is at least intuitively obvious.  It is also possible to play games
with character types and CHAR/ICHAR (assuming that you are on a system
with 8-bit characters), but that is, if anything, more confusing than
using logical.

Probably the "safest" (most standard and portable) thing to do is to
represent 4 (or more) of the 8-bit quantities in a single 32-bit (or
more) integer as in "ipacked = ((i1*256+i2)*256+i3)*256+i4" (assuming
here that the i1-i4 are unsigned).  I've never yet seen a FORTRAN
implementation with less than 32 bits in an integer.  This approach
is sometimes reasonable, but in other applications the performance
hit is too large, particularly if you try to make the code more clear
by hiding the packing/unpacking stuff in separate functions.

I can think of 2 reasons for needing 8-bit integers.  The most
obvious is to save space if you have a big array of em.  The other
reason is to deal with binary files having such 8-bit integers.
(TeX anyone?  Yes, I wrote a TeX device driver in FORTRAN).

I will make no attempt to argue what the "best" solution is to
the 8-bit integer requirement.  I just want to point this out
as a reasonably defensible rationale for using the strange
construct of putting integer values in logical variables on
a VAX.  Of course, not all cases use the construct in this way
or for this purpose.  In some cases it is incomprehensible
to me why such a strange construct was used.  (Should I draw
parallels to strange do-loop structures? Nahh, better not:-))

P.S. Forgot to mention another way to handle 8-bit integers -
code in Pascal or c, or maybe the 8x integer kind= construct,
but that's a different discussion.

Richard Maine
maine@elxsi.dfrf.nasa.gov

brainerd@unmvax.unm.edu (Walt Brainerd) (04/29/89)

In article <MAINE.89Apr28085934@drynix.dfrf.nasa.gov>, maine@drynix.dfrf.nasa.gov writes:
> 
> While acknowledging that this is all non-standard and non-portable and
> ...
> what's a guy to do?  My "favorite" system, the Elxsi, allows
> an integer*1 type (signed), which is admitedly still non-standard, but

The kind parameter for logicals (and all other intrinsic data types)
proposed for Fortran 8?
will allow the implementor to do this according to standard,
and if the programmer is careful, allow it to be used in a portable way.

> "ipacked = ((i1*256+i2)*256+i3)*256+i4" 
 
This ain't gonna work too well on a decimal machine!
Of course,  the author acknowledged that this is nonstandard
and nonportable.  I hope there are fewer and fewer who know this,
but I used to run into lots of Fortran programmers who didn't!

brainerd@unmvax.unm.edu (Walt Brainerd) (04/29/89)

In article <64@unmvax.unm.edu>, brainerd@unmvax.unm.edu (Walt Brainerd) writes:
> Of course,  the author acknowledged that this is nonstandard
> and nonportable.  I hope there are fewer and fewer who know this,
> but I used to run into lots of Fortran programmers who didn't!

Sorry, I left out a "don't" after "fewer and fewer" !