Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29229 Discussions

Negative exponential should be compiler error - instead gives wrong answer

caplanr
New Contributor I
15,485 Views

Hi,

A colleague of mine noticed a bad behavior of IFX (and IFORT) for Fortran regarding negative exponents without parenthesis.  

From our understanding, the Fortran standard does not allow this:

program negative_exponent
  write(*,*) '10.0**-2 * 2=', 10.0**-2 * 2
end program negative_exponent

However, the above code compiles and runs using gfortran, nvfortran, ifort, and ifx.

On gfortran, it gives a warning about the syntax but then "does the right thing":

```
> gfortran negative_exponent.f90
negative_exponent.f90:2:37:

    2 |   write(*,*) '10.0**-2 * 2=', 10.0**-2 * 2
      |                                     1
Warning: Extension: Unary operator following arithmetic operator (use parentheses) at (1)
> a.out
 10.0**-2 * 2=   1.99999996E-02
```

Using NVIDIA's nvfortran, there is no warning but the code gives the right answer:

```
> nvfortran negative_exponent.f90
> a.out 
 10.0**-2 * 2=   2.0000000E-02
```

However, on ifort or ifx, there is no warning and gives the wrong answer:

```
> ifx negative_exponent.f90
> a.out
 10.0**-2 * 2=  9.9999997E-05
```

It seems to me that this code should ideally throw a compiler error since it is not allowed in Fortran (maybe have a flag to ignore the error?).

However, if it IS going to be allowed, it should give the right answer following standard math PEMDAS in compilation.

 

 - Ron

64 Replies
GVautier
New Contributor III
7,732 Views

And what about?

rtCOP_e = 4.82e-6*te**-0.55*1.0e-6
real(8),parameter :: var1 = 4.82e-6
real(8),parameter :: var2 = -0.55
real(8),parameter :: var3 = 1.0/1000000.0
rtCOP_e = var1*var3*te**var2

I always define a PI function as

real(8) function pi()
pi=dacos(-1.d0)
end function

It ensures that trigonometrical results as (cos(pi()), sin(pi() ...) will be accurate

0 Kudos
mecej4O
Novice
4,746 Views

Using pi() in an expression, without a prior type declaration, carries the risk of the function being treated as type real, default kind, which may be less precise than desired/expected.

0 Kudos
caplanr
New Contributor I
6,173 Views

Not to mention that someone could (in about 5 minutes) use AI to easily make a python script that puts exponents in their fortran code according to how they assumed they worked/assumed.

 

0 Kudos
GaborToth
Novice
5,519 Views

I am not AI, but I wrote a Perl wrapper around ifort/ifx/gfortran that spots and reports the actual error, but not the correctly evaluated signed exponent. Here is the test file:

program exponent

  implicit none

  real:: a = 10.0, c = 2.0

  integer:: b = 3

  write(*,*) '10^+3+2/2=', a**+b+c/2

  write(*,*) '10^-3-2*2=', a**-b-c*2

  write(*,*) '10^+3*2=', a**+b*c

  write(*,*) '10^-3*2=', a**-b*c

  write(*,*) '10^+(2*2)/2=', a**+(b*2)/c

  write(*,*) '10^-(2+1)/2=', a**-(b+1)/c

end program exponent

Bugs>ifort exponent.f90 

ERROR: using signed exponent followed by * at line 8 in exponent.f90:

  write(*,*) '10^+3*2=', a**+b*c

--------------------------^

ifort and ifx evaluate the * operator BEFORE the exponentiation!!!

gfortan and nvfortran evaluate the * operator AFTER the exponentiation!!!

Add parentheses to clarify the expression and make your code portable!!!

ERROR: using signed exponent followed by * at line 9 in exponent.f90:

  write(*,*) '10^-3*2=', a**-b*c

--------------------------^

ifort and ifx evaluate the * operator BEFORE the exponentiation!!!

gfortan and nvfortran evaluate the * operator AFTER the exponentiation!!!

Add parentheses to clarify the expression and make your code portable!!!

ERROR: using signed exponent followed by / at line 10 in exponent.f90:

  write(*,*) '10^+(2^2)/2=', a**+(b*2)/c

------------------------------^

ifort and ifx evaluate the / operator BEFORE the exponentiation!!!

gfortan and nvfortran evaluate the / operator AFTER the exponentiation!!!

Add parentheses to clarify the expression and make your code portable!!!

ERROR: using signed exponent followed by / at line 11 in exponent.f90:

  write(*,*) '10^-(2+1)/2=', a**-(b+1)/c

------------------------------^

ifort and ifx evaluate the / operator BEFORE the exponentiation!!!

gfortan and nvfortran evaluate the / operator AFTER the exponentiation!!!

Add parentheses to clarify the expression and make your code portable!!!

negative_exponent.f90 contains 4 errors, so it cannot be compiled

Note that the correctly evaluated lines were not flagged.

 

GVautier
New Contributor III
3,449 Views

No need for an AI. Searching for something like that \*\*[+-] is not very difficult would point out all problematic expressions. Then a regular expression search/replace could correct automatically almost all those problems. 

0 Kudos
Steve_Lionel
Honored Contributor III
2,752 Views

I continue to disagree that the Intel results are wrong. If you accept the extension of consecutive operators, then you should follow the Fortran rules for operator precedence which make unary minus lower than multiplication. That another compiler chooses to ignore Fortran precedence rules in this case feels wrong to me, but again, it's non-standard so anything goes.

This supports my longstanding advice to do a test build with standards warnings enabled, just to see if you're using an extension you didn't expect. You should strive to use only standard-conforming code, unless there is no reasonable alternative, and then you should document it in the comments. I give no weight to "well, it has worked the way I want for years..."

0 Kudos
PeteRiley
Novice
2,532 Views

Dear Steve, 

The fact that three reputable compilers disagree shows this isn’t obviously determined by Fortran precedence; it’s an ambiguity introduced by the extension. 

Going back to your earlier question/point: Do the majority of Fortran programmers actually expect Intel’s precedence here? From the evidence in this thread (and the fact that gfortran, nvfortran, and NAG all either reject or interpret it differently), it seems more likely that most people would expect a**-b*c to mean (a**(-b))*c, i.e., what you’d get if you were following normal mathematical intuition. But, obviously, we only have half the data, and, as you point out, switching this might cause complaints (although I doubt it). 

So I think the trade-off isn't between correctness and backward compatibility, but between continuing to surprise the majority of users (with results that differ by orders of magnitude), or inconveniencing the relatively few who might depend on the legacy parse, but who can be supported with an explicit switch. 

I'm happy for us to disagree on this, of course (and discussing this as a who's right or wrong issue isn't the best approach IMO). But there is a compromise that seems to address both perspectives. Several people in this thread (caplanr, GaborToth) have already suggested the idea of a documented opt-in compatibility switch. Wouldn't that work for everyone? 

-Pete

 

Steve_Lionel
Honored Contributor III
2,525 Views

Pete, it isn't "Intel's precedence", it's the Fortran language's precedence. These other compilers are pretending that unary minus (or plus) after another operator has the highest precedence, which is inconsistent for the behavior without consecutive operators.

The best solution is for people to code to the standard and use parentheses rather than rely on implementation-dependent interpretation. That compilers disagree on non-standard behavior is nothing new. TBH, I've come around to NAG's position that extensions are disabled by default, though I know many users would howl at this. NAG has options for many popular extensions, but you must ask for them. It's a very different world than it was in the late 1970s and 1980s.

0 Kudos
AlHill
Super User
2,520 Views

This is an interesting discussion.  However, I am still bewildered as to why one would not code using paremtheses.  I would want some code maintainer/converter/reviewer to know exactly what my intentions were when I coded it.  I believe you should never assume anything.

 

Just saying.

 

Doc (not an Intel employee or contractor)
[AI is the same as snake-oil]

0 Kudos
Steve_Lionel
Honored Contributor III
2,378 Views

Doc, the fundamental cause of this problem is the way the Fortran language handles unary minus, especially when applied to a numeric literal. Most other programming languages treat something like -4 to be a fundamental entity ("primary" in Fortran-speak), but Fortran does not, and this leads to just this sort of situation. Instead, the minus is just an arithmetic operator and gets handled according to the language's rules for precedence and association. 

Of course, this wouldn't be an issue if compilers back in the 70s and 80s hadn't added extensions willy-nilly, in an attempt to out-do competitors (or more often, copying extensions other compilers had.) DEC was as guilty of this as any of the vendors, if not more so. I imagine the consecutive operators thing just seemed reasonable at the time, but it does lead to errors, as this thread shows. There have been many occasions where I longed for a time machine to go back and try to talk sense into the developers. I did, while I was on the project, did manage to get the team to turn off some of the extensions that caused the most problems for users, such as free conversion between logical and numeric in list-directed input. That it still exists in expressions is problematic, too, but a lot of people have code depending on it so at best I fall back on my advice to do a test build with standards warnings enabled.

0 Kudos
AlHill
Super User
2,375 Views

"DEC was as guilty of this as any of the vendors, if not more so. "  

 

I remember that quite well.  I was on a project (a proposal) for the FEDs back then, and discovered that the government benchmark could only run on DEC Fortran.  There were four bidders:  Dec, Prime, DG, and Wang.  When I reported the issue, saying that the government had wired this proposal so only DEC could win, the government decided to pay Prime, DG, and Wang $500K each to withdraw their proposals, which they did.  DEC got the contract and I suspect the delivery vans were driving around the beltway waiting for the ink to dry.  The thing that made me angry was that the government specifically stated "Fortran Standard", yet the benchmark was written to use DEC's extentions.

 

This made the press in one of the government rags back then.

 

Doc (not an Intel employee or contractor)
[AI is the same as snake-oil]

0 Kudos
Steve_Lionel
Honored Contributor III
2,345 Views

@AlHill wrote:

he thing that made me angry was that the government specifically stated "Fortran Standard", yet the benchmark was written to use DEC's extentions.

Indeed, I heard from many users that they considered certain DEC extensions as "standard" - STRUCTURE/RECORD for example, but I give props to DEC for introducing this one in 1985 as it was clear that "Fortran 88" wasn't going to happen, and it was a capability a LOT of users wanted.

But I have no sympathy for "syntactic sugar" extensions such as consecutive operators.

0 Kudos
mecej4O
Novice
2,000 Views

SteveLionel: "But I have no sympathy for 'syntactic sugar' extensions such as 'consecutive operators'"

This reminded me of

Alan Perlis: " Syntactic sugar causes cancer of the semicolons."

0 Kudos
mecej4O
Novice
1,996 Views
0 Kudos
PeteRiley
Novice
2,507 Views

Hi Steve, 

I appreciate your point about the precedence, but it's the effects that still concern me. After a bit of a rabbit hole search, there are quite a few threads on the topic, and it seems that the extension was motivated by legacy DEC compiler behaviour and optimisation strategies (reassociation for performance). 

I agree that the best solution is for people to use parentheses. But, as a scientist first, and programmer second, I sometimes forget these things. (Don't tell anyone, but I still miss COMMON blocks). 

I like your suggestion of disabling the extensions by default. That would seem to cover everything in that it's consistent with the Fortran standard, and both sides of the interpretation of what the statement means would have to explicitly declare it, either by adding in the parentheses or the extension. 

Pete

garraleta_fortran
2,306 Views

He has worked in Fortran since 1969.
IBM 7090
IBM 1130
IBM 360
IBM 370
IBM 3090
VAX (VARIOUS MODELS)
CRAY 1
CRAY XMP
COMPAQ VISUAL FORTRAN
INTEL Visual Fortran XE 13 Compiler
INTEL ONEAPI

And the rule has always been to include enough parentheses to avoid any cofusion

DONALD H. KNUTH in the book "The art of computer programming" insists on the same

0 Kudos
MarcGrodent
Novice
2,250 Views

I've tried with Matlab, python and R just for fun:

 

Matlab: 10^-2*2 = 0.02

python: 10**-2*2 = 0.02

R: 10^-2*2 = 0.02

 

All of them produce the result almost all of us would expect.

 

 

0 Kudos
Ron_Green
Moderator
2,251 Views

This is a good discussion.  I will bring this issue to the team once again.  We will consider the feedback from this post and give consideration to all arguments.  

 

caplanr
New Contributor I
2,189 Views

It would seem to me, that the way Fortran handles unary minus is fine, when combined with the rest of the Fortran specification.

It is when compiler extensions are added that it becomes an issue.

Given the compiler extension to allow no parenthesis in exponents, how should 10**-2*2 be handled?

1) Do we assume the user is an expert in every detail of the Fortran standard and semantics -  including how it treats unary minus -  but is somehow unaware of a single part of the standard - needing parentheses in an exponent with a sign?

OR

2) Do we assume the user is a scientist that may not be familiar with every detail of the standard and forgets/doesn't-want-to use parenthesis, but who of course would expect PEMDAS to be adhered to in a programming language designed to be a FORmula TRANslation of mathematical equations?

 

IMO, the answer seems obvious.  The extension was almost certainly made for the second individual above, and therefore the non-standard Fortran should follow standard math (like every other compiler that allows the extension).

Otherwise, the compiler should fail to compile and require the user to follow the Fortran standard.

If the desire to not need parentheses from users is so great, than the ISO Fortran team needs to get together and update/change the standard in 202Y.  Either to not need them, or to change how unary sign is handled.

 - Ron

0 Kudos
mecej4O
Novice
2,182 Views

There is one more point of view that should be given some consideration as part of the decision to leave the compiler as is or to alter its default behavior. If the expression under question is not standard-conforming, but has existed in widely used code for decades, it is likely that the author(s) made reasonable attempts to make the code standard-compliant at the time of creation, given the widely used Fortran machine/compiler combinations available to them and it is equally likely that their colleagues exercised and tested the code segment several times and found it worked as they expected; what would be a reasonable guess for the semantics that they regarded as acceptable?

The authors' guide of the Physics Review Letters journal states:

 "Put in extra bracketing even where convention does not require it, if a likely misreading is thereby avoided. But leave them out where they would merely clutter the picture." 

That strikes me as good advice even for Fortran source code.

0 Kudos
Dave_Allured
New Contributor II
2,076 Views

People need to be actively warned when they are using nonstandard ambiguous code that could result in hidden numerical errors with possible severe consequences.  You can not expect the entire user base to use the -strict flag or a code scanner.

I ask the Intel team to reconsider.  Here is a specific refinement of the above suggestion #2 from GaborToth.  Add two new flags to Intel fortran, plus default:

  • (default) -- Consecutive operators generate a hard compile error, with informative message.
  • -allow nonstandard_consecutive_operators -- Consecutive operators compile to Intel-specific interpretation, and informative warning is printed.
  • -allow nonstandard_consecutive_operators_no_warning -- Consecutive operators compile to Intel-specific interpretation, and no warning is printed.

Documentation should be updated with an explicit warning that different compilers have completely different interpretations of this nonstandard construction, and will generate divergent numerical results.

This should provide the right degree of caution, while satisfying everyone's diverse needs.  Since the Intel compiler is already detecting this specific condition, it should be easy to convert existing behavior into this precautionary approach.

I am generally enthusiastic about legacy support extensions in compilers, but this one is dangerous and scary.  I would be glad to be warned that any of my legacy code is using a dangerous nonstandard construct, and to add a handful of extra parentheses.

0 Kudos
Reply