I am a bit surprised that many people (in this thread) have so much “feeling” or opinions about .eqv.
or .neqv.
, because it is very rare that I need to use them up to now. For example, I’ve just tried grep
for .eqv.
with a code in hand (~90k lines), which shows only 4 .eqv.
used in some check with assert
macros like assert(flag1 .eqv. flag2)
). In other cases, I just write if (myflag)
etc rather than if (myflag .eqv. .true.)
, so it does not appear very often… So I am wondering about how .eqv.
etc are used in other codes.
I can’t answer for @urbanjost but I’ve certainly needed it in an xor context. My main gripe then was that .neqv. would be better named as .xor.
I have thought this too in the past. The logical operator set does not correspond exactly to the bit operator set in this case. The .eqv.
and .neqv.
operators are symmetrical opposites. By that I mean the following
.eqv.| T F .neqv.| T F
------------ -----------
T | T F T | F T
F | F T F | T F
You can see that x.neqv.y
is the same as .not.(x.eqv.y)
(and visa versa). The language could have dropped the .neqv. operator altogether and required the programmer to write it out the long way (or visa versa). But if you write the similar tables for the .or.
and .xor.
operators (the latter being an extension), they do not have this symmetry, they are distinct, independent, operators.
For the bit operators, IEOR()
corresponds to .neqv.
, and NOT(IEOR())
corresponds to .eqv.
The two sets of operators do not correspond for the .eqv.
case. I have always thought it would have been much simpler in the language if the same conventions had been applied to both cases (logicals and bits), and if the logicals themselves could be used directly in integer contexts such as array indexes and arithmetic operations. But that isn’t what happened, and it would be too disruptive to change it now.
There are already over 60,000 preprocessing fences in the library. We abandoned the verbosity/complexity concerns several years ago when we had to rely on compiler flags to relax undesirable standard constraints (like 132 maximum line length, …). I use overloading frequently. But I am still somewhat uncomfortable relying exclusively on the compiler to inline overloads from other modules for such simple tasks where performance matters.
Perhaps a good solution forward, without breaking backward compatibility and any performance penalties, would be the addition of re-use
-able module macros in the future standard to handle cases like what is discussed here. Then things like the above FPP snippet we replicate over 100 times in the library could be defined only once and use
d everywhere.
Well, if you believe the x86 home hobbyist computer is good enough to run a business on, then I understand your confusion. Before you can make sense of the answer you have to understand what Enterprise Class Computing is.
Second reply due to link limitations
I took a quick glance at the HP Fortran manual I could find. I didn’t see all of the FOR /qualifiers listed I wanted to see. The VAX and PDPD FORTRAN compilers had hundreds of switches to control input sources. You see, no two companies had the same computer systems back then, but they all had to exchange data on tape. This meant your program or your enterprise class operating system had to deal with LABEL RECORDS ARE STANDARD, Big-Endian vs. Little-Endian, the fact that PACKED-DECIMAL had slightly different encoding between DEC VAX and IBM and some of the lesser now forgotten platforms didn’t even support it. Almost every platform of the day used a different FLOATING POINT standard. Heck, the DEC BASIC compiler used two different ones, neither of which were the one the COBOL compiler used by default which was okay because PRIME, MAI BASIC-IV, and SINGER all did their own thing as well.
Adding insult to injury, there is no data type standard for a logical. Each platform was allowed to use the most efficient data type. Some used a byte despite the inefficiencies of that data type. The smallest unit they could move was generally a register size and that was generally at least a LONG (4 bytes).
Now, if you move a 1 to a “logical” that is a LONG on both a Big-Endian machine and a Small-Endian machine, when the data is transferred between, if you have a toy OS, you have two dramatically different values.
Third reply because of link limitations.
Those who have known only the home hobbyist x86 have never heard of the computers that were and will be again, Analog. These computers were not binary, yet they had FORTRAN compilers. This type of computer is coming back because there are a large class of problems digital computers are simply unfit for.
Analog computers understand “kinda.” Something can be “kinda true” and “kinda false.”
.EQV. exists in FORTRAN because we’ve always needed to understand “kinda.”
Who are you answering to?
Sorry but none of your explanations appear to have any relevance whatsoever to the discussion on hand, they don’t explain as to why the Fortran standard
- first introduced in
ANSI X3.9 FORTRAN 77
the.EQV.
as a logical equivalence operator as distinct from relational equality operator.EQ.
, particularly when
a) the semantics of a Logical Type where clear definitely byANSI X3.9 FORTRAN 66
that "A logical datum may assume only the truth values of true or false.,
b) The standard is meant to be driven by its semantics, not how processor A might have done something relative to another one and so forth,
c) Somewhat of a similar underlying representational variances when it comes to relational equivalence/equality could come about with theCHARACTER
type also but the.EQ.
was extended to coverCHARACTER
type butLOGICAL
, - Then in the next revision Fortran 90, there could have been convergence on to the new
==
operator but all the other types got covered exceptLOGICAL
.
Note there is really no usable binary compatibility in data transfer across Fortran processors, at least none that is even remotely comprehensively addressed in the standard, so none of those considerations ideally would apply to LOGICAL
type.
Sorry, there is no logical explanation for .EQV.
in Fortran other than:
- Committees make mistakes,
- Committees cannot fix its own mistakes.
Sorry, forgot the @Harper
@FortranFan My explanations make perfect sense. The FORTRAN 77 standard was created for Enterprise Computing, not the x86 hobby computer world. I’ve actually had to process files from disparate computer systems on PDP running RSTS/E and VAX running VMS. I’ve actually had to use many of those FORTRAN /qualifiers to build stuff to handle the input sources.
That would be incorrect. Just who do you think was on the standards committee at the time?
They all apply.
For some run-time implementations of LOGICAL where the values are locally declared in a program but not stored it is a bit masked out of a Quadword where all of the other runtime LOGICAL values exist.
Which is not required to be binary.
A really good example would be $STATUS on OpenVMS. SUCCESS (truth values) are positive. Failure (false values) are negative. Both 1 and 32,767 are SUCCESS values but 1 != 32767
I have seen that kind of usage in Fortran, and not too long ago. I was helping someone port a code to his programming environment and one bug came down to a line that was counting the number of .true. values in a logical array not getting the right value.
The array was equivalenced to an INTEGER array. The original environment assumed odd values were .true. and .false. values were even; which is an interesting if non-portable method!
Using just the least significant bit in the storage unit is one of the common conventions for logical true/false values. I’m curious if there exists anywhere a list of the various internal conventions and which compilers/vendors used which of the conventions?
Regarding the original question of why logicals do not use .eq., I would guess that some time back in the early days of fortran in the late 1950s or early 1960s, someone compared logical values that had been set previously through integer assignments and got the wrong result. So the “solution” in the next version of the compiler was to have different comparison operators for the two types. So no deep thought into semantics, symmetry, or orthogonality, just a hack, and it stuck through the various language standard revisions to today. That is just a guess at what might have happened.
If it emerges that many people have a use for such information, one could construct a function L1MACH to add to the set I1MACH, R1MACH and D1MACH.
The following little program demonstrates that different compilers use different representations of logical values, and it is going to be not so easy to write portable programs that save logical values into unformatted files.
program l1mach
integer li,lj
logical la,lb
!
la = .true.
print '(1x,Z8.8)',transfer(la,li)
la = .false.
print '(1x,Z8.8)',transfer(la,li)
la = .not.la
print '(1x,Z8.8)',transfer(la,li)
li = Z'80000000'
print '(1x,L8)',transfer(li,la)
li = Z'00000002'
print '(1x,L8)',transfer(li,la)
li = Z'0000000F'
print '(1x,L8)',transfer(li,la)
end
On Windows, Ifort gives
FFFFFFFF
00000000
FFFFFFFF
F
F
T
whereas Gfortran and Ifort with the option /fpscomp:logicals give
00000001
00000000
00000001
T
T
T
Ah. That is a nice approach. I was using a little program to probe a few compilers too.
Machines that distinguish between 0 and -0 might be an issue. I was just looking at what
switches might be available.
Without stooping to actually reading the manual, this little program tells a lot; I think I will merge it with yours and add a few asserts and add COMPILER_OPTIONS() for fun.
program curious
use, intrinsic :: iso_fortran_env, only: int16, compiler_version
implicit none
character(len=*), parameter :: all = '(*(g0,1x))'
integer :: i
integer, parameter :: pr = 20, sz = max(1024, pr)
integer :: ifew(-sz:sz) = [(i, i=-sz, sz)]
logical :: lfew(-sz:sz)
print all, 'This file was compiled by ', compiler_version()
lfew = transfer(ifew, [.true.])
print all, count(lfew), '/', sz, transfer(.true., 255), transfer(.false., 255)
print all, lfew(-pr:pr)
ifew = transfer(lfew, [255])
print all, ifew(-pr:pr)
end program curious
$ ifx curious.f90
$ ./a.out
This file was compiled by Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2023.0.0 Build 20221201
1024 / 1024 -1 0
F T F T F T F T F T F T F T F T F T F T F T F T F T F T F T F T F T F T F T F T F
-20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$ gfortran curious.f90
$ ./a.out
This file was compiled by GCC version 11.1.0
2048 / 1024 1 0
T T T T T T T T T T T T T T T T T T T T F T T T T T T T T T T T T T T T T T T T T
-20 -19 -18 -17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Modal logic can deal with “kinda”. As well as “true” and “false” it allows “necessarily true”, “possibly true”, “possibly false” and “necessarily false”. Over 60 years ago neither my professor nor I knew about that when he had set an assignment to prove something was a necessary and sufficient condition for something else. I handed in a proof of sufficiency but I also said the condition was not necessarily necessary. He was not impressed.
It has often happened in mathematics that when something is not necessarily necessary or sufficiently sufficient a new kind of arithmetic/algebra/analysis can be invented to overcome the deficiency. For example, integer → rational → irrational → transcendental; real → complex → finite-fields; Riemann → Lebesgue → Denjoy integrals; factorial → gamma function; etc.
.EQV.
has nothing to do with kinda
, Fortran kinda has little to no support for kinda
!
Nor does things like $STATUS have any relevance to the Fortran standard; there kinda isn’t anything in Fortran akin to things like “success” type on certain OS whose integral representation might take on two or more bit sequences.
Instead Fortran has notions like `stat-specifier" with semantics such as, “Successful execution of blah blah blah causes the stat-variable to become defined with a value of zero.”
And “Execution of … causes the scalar-logical-variable in the … to be assigned the value true if …; otherwise, false is assigned.”
On the basis of the language standard as it stands alone, there really is no logical basis for the asymmetry re: ==
other than as stated above re: committees and mistakes. “Let the sleeping dog lie” might be the take of many …
Logical operators were not mistakes.