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

Negative exponential should be compiler error - instead gives wrong answer

caplanr
New Contributor I
16,633 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

66 Replies
GVautier
New Contributor III
7,896 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,910 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,337 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,683 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,613 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,916 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,696 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,689 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,684 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,542 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,539 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,510 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,165 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
JohnNichols
Valued Contributor III
123 Views

I can remember times past when I used the term syntactic suger from Perlis and the comments were quite negative.  

0 Kudos
mecej4O
Novice
2,161 Views
0 Kudos
JohnNichols
Valued Contributor III
123 Views

The planets aligned - I agree with Al and it is not even the Ides of March.

0 Kudos
PeteRiley
Novice
2,671 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,471 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,415 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,416 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,354 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
Reply