Trouble with Logical .AND. Operator

Trouble with Logical .AND. Operator

Compiling a purely Fortran program -- self-contained exe --with the following options generated through the MS VisualStudio 2003.NET (a la Visual C++.NET):

/nologo /Zi /Od /include:"Debug/" /fpscomp:filesfromcmd /fpscomp:ioformat
/fpscomp:logicals /fpscomp:general /error_limit:10 /warn:errors /warn:unused
/warn:interfaces /real_size:64 /Qsave /align:rec8byte /align:dcommons
/assume:dummy_aliases /Qzero /fpe:0 /iface:cvf /module:"Debug/" /object:"Debug/"
/traceback /check:bounds /check:format /libs:qwin /c

I'm getting an erroneous ".TRUE." with the following code which is in a .f90 source file. I am linking it witha large number of .for files, but all the action involved in this erroris local to the .f90source. (Line numbers are for reference only and not included in the code):

1 Logical a,b

2 x=1.
3 y=2.
4 a=.TRUE.
5 v=0.
6 if(v=0.)b=.FALSE.

7 if(a .AND. b)then
8 p=x/v
9 else
10 p=x/y
11 endif

Line 8 gets executed whenever a is .TRUE. (according to the cursor-hover help in MSVS2003.net), regardless of the value of b... not a nice thing when I have a zero in v.

Any ideas on what I might be doing wrong would be greatly appreciated.

Thanks and God bless!
Jack O'Sullivan

God bless!
26 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
Steve Lionel (Intel)'s picture

I would ask that you verify that line 8 is actually being executed and that it isn't just the debugger making a mistake. PC-line correlation information can sometimes be flaky.

I will also say that sometimes I see paraphrasing of code that doesn't match the actual code. If you can show that the wrong line is actually being executed, please create a complete test case and submit it to Intel Premier Support.

Steve

In fact, the way you have quoted the code, it should throw a compile error. If you wrote the same kind of thing in C, and disabled warnings, you would get the kind of behavior you report.

Steve Lionel (Intel)'s picture

Tim, I don't see the error. What is it?

Steve

On my screen, it shows if(v=0.) ....
where if(v == 0.) ...
might have been meant.

Steve Lionel (Intel)'s picture

Good eyes! However, I am pretty sure that this is a "representation" and not the actual code. An easy typo to make (I've done that myself too many times.) You're right that in Fortran this would be a syntax error and in C a different meaning.

Steve
Paul Curtis's picture

Logical quantity b is undefined (defaults to .FALSE.?) in the code as written.

Perhaps line 6 should read

b = (v /= 0.)

which always explicitly assigns the value of b.

Steve Lionel (Intel)'s picture

True enough, though if the code shown is an accurate representation, b should be set to .FALSE. because v is zero. There is no default initialization here. My guess is that the actual code does something different.

Steve

Thanks, folks, for your attention to this. Sorry to have put you all to such trouble.

In following Steve's initial "homework assignment" to create and submit a complete test case, I found the error -- one which I do believe should have been caught by the compiler.

Steve correctly recognized the bad paraphrase with the = rather than ==, and my paraphrasing of the problem area of the program was definitely incomplete.

It turns out that what caused the error -- even though I have called for the compiler to treat all warnings as errors -- was a duplicate specification of one of the logical variables.

A true extract of thesubroutine is shown below:

SUBROUTINE lngvalv [from .f90]
! -- removed from the CONTAINS in the subroutine which now calls
! this one because the IVF interface to Visual Studio does not
! permit debugging of the containER variables when in the
! containED portion of the source file
....
use mlimits
 [which is as follows from .for:
 module mLimits
 integer(4), parameter ::
 &maxsecno=20000
 &,maxvalv=300
 ....
 end module mLimits]
....
use mValpc
 [which is as follows from .for:
 module mValpc
 use mLimits
COMMON/VALPC/T01(21,maxvalv),S01(21,maxvalv),STK(21,maxvalv) & ,COD(21,maxvalv),TQ,VALDIM(maxvalv) 1 ,COEF,NCRV1(maxvalv),NCRV2(maxvalv) ,KKK,SX,ITIM,ISTK &,THETO(maxvalv), 2 THETS(maxvalv),DELH,IOPG(maxvalv),TV(maxvalv),ICHKV(maxvalv) &,CDN(21,maxvalv),VVN(maxvalv),NCV2
save /valpc/
end module mValpc ]
....
use mvalvlng
 [which is as follows from .for:
 module mValvLNG
 use mLimits
 DOUBLE PRECISION BB,CC,C1R,C1S,C3,C4,TA,TA2
 1 ,vv,vu,vd,pvv,voidu,voidd,hvvap,hu,hd,hv
 logical undecided,separate
 common/ValvLNG/bb,cc,ta,ta2,c3,c1r,c4,c1s,vu,vd
 1,vv,pvv,voidu,voidd,hvvap,hu,hd,hhv,tjlngmax
 1,i7,ii7,L7,LL7,iop9,jlngmax,idin,kk,undecided,separate(maxvalv)
 1,i1,i2,i3,i4,i5
 1,ii7vs,i7vs
save /ValvLNG/
&nbs
p; end module mValvLNG]
....
LOGICAL :: upst,dnst,joined,separate(kkk),previouslyseparated
....
joined=.true.
....
previouslyseparated=separate(kkk)
separate(kkk)=.false.
....
if(joined .AND. previouslyseparated)then
[divide by zero] <<<<
else
[use another relationship]
endif
....
You'llnotice that the highlighted LOGICAL "separate" is specified both
in the module mvalvlng and in the subroutine itself -- the accidental 
result of an unthinking Copy/Paste.
The only hint of trouble came when run-time stopped me with a divide-
by-zero at the line I've flagged with <<<<
Question 1: Would this error have been caught had I used the
old-fashioned INCLUDE-a-source-file rather than the de rigueur
USE-a-module to get my variables specified?
I suspect this would have been caught had I been able to follow Steve's
earlier advice to run the Static Verification.  But all that does is bomb
out -- without any 'scuse me's at all! -- after trying to grab more RAM
than the IA-32 system has available. 
This last problem I have reported to Intel Premier Support, only to be
politely advised by Xiaoping Duan, [T]here has already been a known
report on huge memory usage by SV leading to out of memory. The main 
reason is that we keep info in memory for all routines simultaneously. Keeping unneeded info results in 'out of memory' error. The developers have already fixed it and the fix will be available in future 10.1 update. I will associate your problem report to the existing bug report and let you know when the new compiler containing the fix is available. [Emphasis added.]

Question 2: When will 10.1 be available? Even a Beta would be lots
better than flying blind like this!

Quest
ion 3: When, oh when, are They going to fix this Message
dialog so that you can force it to return to automatic word-wrap
after pasting code??!!
Shift-Return is not one of my favorite
punctuation marks!

Question 4: When are "They" going to make this Message dialog
the same width as the Thread presentation window??!!
Sliding
the window from right to left is not my favorite way to read things!

Thanks again to all, and of course, God bless!

Jack OSullivan

God bless!
Steve Lionel (Intel)'s picture

Unfortunately, the mistake you made is perfectly legal Fortran so the compiler could not "catch" it. Uninitialized variable checking might have found it.

I'm glad to hear that you solved the problem. (Note - it was Tim who spotted the = typo.)

This is another illustration of the confusion caused by paraphrasing the code - in almost all cases the actual error is in code you did not show.

Steve

Steve,

If this is "perfectly legal Fortran", how is it that during a debug session I would get the divide by zero when the values of joined and previouslyseparated are revealed via cursor hovering to be .TRUE. and .FALSE. respectively, and the hover-revealed value of "(joined.and.previouslyseparated)" shows as .FALSE.?

The parentheses served as a proper gate, preventing the divide-by-zero as soon as I removed separate(kkk) from the LOGICAL statement.

Thanks again, asnd God bless!

Jack

God bless!
Steve Lionel (Intel)'s picture

Upon rereading your expanded code, I'm still not quite certain of what the problem was. Ignore my comment about "perfectly legal". If you have a locally declared name that is the same as a USE-associated name, the compiler will complain. If I saw the whole application, I might then understand the issue and perhaps be able to explain it.

Steve

Steve,

I have created a short version that makes the same errors:

1) It does not catch the local plus common/module specification.

2) It does not treat the "a.and.b" as false when its contents are ".true..and..false."

It's a bit long to put here -- 65 lines or so in 5 source files -- so I will submit it to Premier Support.

Thanks and God bless!

Jack

God bless!
Les Neilson's picture

Just a small item tonote : (may not be relevant in this instance but just in case it is)

In the first sample code there is if (v==0)

If "v" in the actual codeisReal and is the result of a calculation then it may not be exactly zero. Tests for equalitywith real/double precision variablesshould be avoided and a tolerance used instead.

Les

Steve Lionel (Intel)'s picture

Jack,

Thanks so much for sending the test program AND your build settings. These were critical to understanding the problems.

First, you are absolutely correct - the compiler should have complained about the duplicate declaration of "separate". It turns out that it does so in most cases, but not when the variable is declared as part of a COMMON in the module. We'll fix that.

The second issue is more interesting and requires your having set /fpscomp:logicals. In the test program, logical variable b is set to an unpredictable value because the local array separate is uninitialized. In the case in question, the value it gets (in my test run) is Z'0040105A'. Because /fpscomp:logicals was set, any non-zero value is TRUE, but the debugger is assuming the default logical semantics where even values (low bit clear) are false, so it displayed the value as .FALSE. even though the code treated it as .TRUE..

I'm not sure how we'll address this second problem - there isn't currently a mechanism to inform the debugger that /fpscomp:logicals was used. There's a couple of possibilities I've thought of and we'll try to figure out a solution for the future.

Steve
jimdempseyatthecove's picture

Jack,

I believe what you are experiencing is a problem of (feature of) name space (scope)and as a result uninitialized variables being used.

module mValvLNG
...
  logical ...,separate
! named common block ValvLNK::separate
! not module name mValvLNG::separate
common/ValvLNG/...
 ...,separate(maxvalv)
 ...
 save /ValvLNG/
end module mValvLNG]
...
(your subroutine/funciton)
use mValvLNG
...
! stack local (subprogram scope) separate
LOGICAL :: ...,separate(kkk),previouslyseparated
....
joined=.true.
....
! using uninitialized stack local
previouslyseparated=separate(kkk)
separate(kkk)=.false.
....
! previouslyseparated contains copy of uninitialized data
if(joined .AND. previouslyseparated)then
[divide by zero] <<<<
else
[use another relationship]
endif

I believe this qualifies as a nested scoping situation where it is valid to re-use the name to declare a different data area of the same name for use for different purpose.

I haven't tried it but I think if the module contained non-COMMON variables that the compiler error you sought would have occured.

Experiment byadding

logical :: separateFOO(maxvalv)

to module mValvLNG on a line by itself and without also being declared in a COMMON

Then in your program where the problem occured insert

logical :: separateFOO(kkk)

immediately following the logical that declared the local copy of separate.

When you compile I think you will see the error message that you were expecting.

Jim Dempsey

www.quickthreadprogramming.com
Steve Lionel (Intel)'s picture

Jim,

Fortran does not allow the sort of nested scoping you describe. As I posted above, it is a compiler bug that it does not detect the error when the use-inherited name is a COMMON variable.

Steve
jimdempseyatthecove's picture

Steve,

>> It turns out that it does so in most cases, but not when the variable is declared as part of a COMMON in the module. We'll fix that.

In this particular case it is a named COMMON block (a seperate scoping unit). I believe it should not be fixed as you would be breaking an F90 standard regarding scoping. Before you put this in for a fix check what the standards committee suggested regarding this situation.

Jim Dempsey

www.quickthreadprogramming.com

Jim ... and everyone else who has joined into this ...

Thanks so much for taking the time and effort to guide this poor ol' hydraulic engineer in the ways and foibles of Fortran. This site truly has the correct name: softwarecommunity!

Steve,

Thanks in particular for your speedy attention to this problem.

Perhaps while you are working on making COMMONvariables visible to the compiler's error-trapper, you might find a way to make the Go To Definition right-click function in MS Visual Studio actually do that for IVF?

Also, any idea of when 10.1 is coming out? I could sure use that Static Verification!

All,

Thanks again so much, and of course, God bless!

Jack

God bless!
Steve Lionel (Intel)'s picture

Jack, I noticed that formatted and list-directed I/O will also assume the default interpretation and not honor /fpscomp:logicals. We're discussing this - one option may be to simply say that /fpscomp:logicals affects how logical tests are done computationally but not display of values.

Jim, my reading of the Fortran 2003 standard makes it clear that the standard does not allow this. Do you have something that shows otherwise?

Steve

Steve,

I'd hope that whatever you do will still let this (and other)realtive unitiate(s) still be able to "see"correct values duringdebug sessions.

Ona programming level, I've been retaining the /fpscomp:logicals option only because the Windows version of "my" program was born in Powerstation lo these many years ago, and I thus thought it would be the right thing to do. Does it make any real difference? Especially if I don't try passing "logical" variables into "boolean" space in other-language routines?

Maybeyou simply want to force all Fortran logicals to become C(?) booleans within your implementation?Or is IVF really more than a transcriberof Fortran source code into a C- (or something-else-) based last stage before it all becomes machine code?

Steve and Jim,

If the Standard sticks you with having to retain ambiguously named data areas, please at least make it the subject of a Warning -- perhaps a selectable one, if you must, but at least a Warning (that I can then turn into an Error if I want).

Thanks again and God bless!

Jack

God bless!
Steve Lionel (Intel)'s picture

No, we're not going to change the default binary interpretation of LOGICALs. I would recommend that you turn off /fpscomp:logicals and see what happens.

Steve
jimdempseyatthecove's picture

Steve,

I have not studied the Fortran 2003 standard. I am consulting the IVF documentation click on "scope" do not click on "of unambiguous..." and combined with info on namedCOMMON blocks. From my understanding of the documentation:

module 1 can create a named common block which contains a variable named X

module 2 can create a differently named common block which contains different variable named X

module 1 and module 2 can be compiled seperately thus creating two copies of X within the scope of the respectivelynamed common.

Subprogram Y using module 1 or module 2 can unambiguously view the host scope named COMMONX.
Subprogram Y using module 1and module 2 can ambiguously view the host scope named COMMON X.
(unambiguously with scoping operator ::)

Subprogram Y can(arguably) create local scope class I variable named X because X as previously declared in USE (either or both) is in a Host scoping unit and thus not declared in the local(sub-ordinant) scoping.

The "(arguably)" is an issue that should have been addressed by the F2003 standard which I have not studied. I defer this to your interpretation of the standard.

Note, if the two modules each contain a module scoped variable named X (i.e. not in COMMON) then a subprogram could not use both both modules... Or at least not use both and then reference X without scoping the variable.

Jim Dempsey

www.quickthreadprogramming.com
Steve Lionel (Intel)'s picture

Jim, that is not correct.

First, there is no "scoping operator" in the Fortran language. The use of :: you mention is a convention we offer in the debugger, that is all.

This is what the standard says:

18 An accessible entity in the referenced module has one or more local identifiers. These identifiers are
19 (1) The identifier of the entity in the referenced module if that identifier appears as an only20
use-name or as the defined-operator of a generic-spec in any only for that module,
21 (2) Each of the local-names or local-defined-operators that the entity is given in any rename for
22 that module, and
23 (3) The identifier of the entity in the referenced module if that identifier does not appear as a
24 use-name or use-defined-operator in any rename for that module.

25 Two or more accessible entities, other than generic interfaces or defined operators, may have the same
26 identifier only if the identifier is not used to refer to an entity in the scoping unit. Generic interfaces and
27 defined operators are handled as described in section 16.2.3. Except for these cases, the local identifier
28 of any entity given accessibility by a USE statement shall differ from the local identifiers of all other
29 entities accessible to the scoping unit through USE statements and otherwise.

So in your scenario, if subprogram Y uses both modules 1 and 2, subprogram Y must not reference the name X.

More to Jack's problem, the standard also says:

30 The local identifier of an entity made accessible by a USE statement shall not appear in any other
31 nonexecutable statement that would cause any attribute (5.1.2) of the entity to be specified in the
32 scoping unit that contains the USE statement, except that it may appear in a PUBLIC or PRIVATE
33 statement in the scoping unit of a module and it may be given the ASYNCHRONOUS or VOLATILE
34 attribute.

This means that the local identifier X that comes from the module must not be named in a declaration in the subprogram, with the exceptions shown. There's no exception for COMMON variables. The standard also has this note:

NOTE 11.10
The constraints in sections 5.5.1, 5.5.2, and 5.4 prohibit the local-name from appearing as a
common-block-object in a COMMON statement, an equivalence-object in an EQUIVALENCE statement,
or a namelist-group-name in a NAMELIST statement, respectively. There is no prohibition
against the local-name appearing as a common-block-name or a namelist-group-object.

Steve
jimdempseyatthecove's picture

Thanks Steve for locating the specification and clarifying the issue.

In what you quoted and stated

Module 1 could have X
Module 2 could have X (different X)
code could use both module 1 and 2 but not reference nor declare it's ownX

Too bad about not having localized scoping such as C/C++{ and } whereby one could declare something ubiquitous such as "TEMP" without running afoul of something in some module that may be supplied by a 3rd party and eventualy clash with a long standing variable name used in someone's application.

BTW withmy programming style I tend to use

module mod_foo
type type_foo
real ::X
integer :: ...
end type type_foo

type(type_foo) :: foo
end module mod_foo

...

use mod_foo
...
foo.X = 1234.

When I convert older files I also create a

! mod_foo.inc
#define X foo.X

Then on compilation units that have "use mod_foo" I also have "#include 'mod_foo.inc'" (and be careful to only #include it once per compilation unit that requires it).

Jim Dempsey

www.quickthreadprogramming.com
Steve Lionel (Intel)'s picture

Yes, this does catch a lot of programmers unawares, and it took me quite a while before it sunk in that, in this regard, Fortran was not like Ada! However, all is not lost - you can use renaming and ONLY to control the imported names so that they don't conflict. In fact, the Fortran style is in some ways better as it catches problems (such as Jack's, if the compiler didn't have a bug here) that would otherwise go undetected.

You can still have a problem with host association, though. The following is legal:

module mymod
integer i
contains
subroutine mysub
integer i
...

In this case, the module variable I is hidden inside routine mysub, which could be a problem if you were expecting to use the shared version. More often I see issues with code such as this:

module mymod
contains
subroutine sub1
external sub2
call sub2
end subroutine sub1
subroutine sub2
...

Here, the "external" declaration, which may be a holdover from an earlier F77-style implementation, hides the module procedure sub2 and refers to some (perhaps undefined) external procedure sub2.

Steve

Login to leave a comment.