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

Negative exponential should be compiler error - instead gives wrong answer

caplanr
Novo colaborador I
15.221 Visualizações

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 Respostas
Ron_Green
Moderador
11.182 Visualizações

Very inconsistent behavior across compilers.  NAGFOR does throw an error and aborts compilation.  Which seems to be the right behavior.  But for sure, Intel's results are incorrect.  I will write up a bug report.

Steve_Lionel
Colaborador honorário III
11.157 Visualizações

As the NAG compiler indicates, it's not standard to have two consecutive operators. I discuss this very point in Doctor Fortran in "Order! Order!" - Doctor Fortran

 

Intel Fortran allows this as an extension, and will complain if you ask for standards checking:

D:\Projects>ifx -stand t.f90
Intel(R) Fortran Compiler for applications running on Intel(R) 64, Version 2025.2.0 Build 20250605
Copyright (C) 1985-2025 Intel Corporation. All rights reserved.

t.f90(2): warning #8810: Consecutive operators are an extension to the Fortran 2018 standard.
  write(*,*) '10.0**-2 * 2=', 10.0**-2 * 2
------------------------------------^

The Intel documentation covers this case explicitly:

---

Ordinarily, the exponentiation operator would be evaluated first in the following example. However, because Intel Fortran allows the combination of the exponentiation and minus operators, the exponentiation operator is not evaluated until the minus operator is evaluated:

A**-B*C is evaluated as A**(-(B*C))

Note that the multiplication operator is evaluated first, since it takes precedence over the minus operator.

When consecutive operators are used with constants, the unary plus or minus before the constant is treated the same as any other operator. This can produce unexpected results. In the following example, the multiplication operator is evaluated first, since it takes precedence over the minus operator:

X/-15.0*Y is evaluated as X/-(15.0*Y)

---

So, 10.0**-2*2 is evaluated as 10.0** (-(2*2)) or 10.0**-4, which is what gets displayed (within the limits of single precision real.)

Not a bug, but an extension. Other compilers are free to interpret this as they like.

mecej4O
Novato
4.624 Visualizações

May I state my mild objection to "operator is evaluated" in the quoted Intel documentation extracts?

An operator has no value, and certainly not without the requisite number of operands being provided in proper juxtaposition.

Ron_Green
Moderador
10.989 Visualizações

You can get a Warning by using the option -stand or -stand f18

Still, it is a bug in the computation. CMPLRLLVM-69904

It's a bug in a compiler transform called "constant folding".


This slightly modified example demonstrates the bug more fully:

$ cat bad_constant_folding.f90 

program negative_exponent

 write(*,*) '10.0**-2 * 3 should be 3.0E-2'

 write(*,*) '10.0**-2 * 3 result ', 10.0**-2 * 3

end program negative_exponent

$ ifx -O0 -stand bad_constant_folding.f90 ; ./a.out


bad_constant_folding.f90(3): warning #8810: Consecutive operators are an extension to the Fortran 2018 standard.

 write(*,*) '10.0**-2 * 3 result ', 10.0**-2 * 3

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

GNU ld (GNU Binutils for Ubuntu) 2.43.1

 10.0**-2 * 3 should be 3.0E-2

 10.0**-2 * 3 result  1.0000000E-06



Steve_Lionel
Colaborador honorário III
10.603 Visualizações

I still don’t think this is a bug. Rather, it’s implementation-dependent behavior of non-standard code. I explained why above - did I get it wrong? That other compilers choose to interpret the non-standard code in a different way doesn’t make it a bug. If anything, the differing interpretations should discourage the reliance on the behavior and encourage the proper use of parentheses.

If this “bug” is “fixed”, I guarantee that you’ll see complaints from other users that their code broke, and you’ll also have to change the documentation. I’d also comment that the documented behavior is far older than any of the other compilers cited here.

andrew_4619
Colaborador honorário III
10.517 Visualizações

What you said Steve is consistent with what the Intel documents says..... Thus it seems to me that this (like it or not) is the intended behaviour, thus the answer is to do nothing. The only other option at this stage would be to flag an error for invalid Fortran and break the codes of anyone that used the extension. From my selfish point of view that would be the better option as to be frank the historic choice doesn't seem very wise IMO .....

caplanr
Novo colaborador I
10.451 Visualizações

The fact that the other major compilers interpret it "correctly" or do not allow it makes Intel an outlier.

It is difficult to think there is production code out there that relies on the "incorrect" math operator precedence in ifort/ifx to the extent the developers never have run the code on gfortran or any other compiler.

Such a thing CAN happen (and I have seen this with some HPC codes that only are ever run on a specific system) but having code like that in a code base sounds like a really bad idea.

I agree that if the Intel compiler does not want to regress the chosen interpretation, it would be better to just not compile it by default and throw an error.

Adding a compatibility compiler flag to allow the compilation using the "Intel interpretation" could allow rare cases to continue to compile their non-conforming code that relies on non-standard math operation orders.

Ron_Green
Moderador
10.420 Visualizações

We had a discussion with the whole team.  The consensus follows Steve and Andrew's recommendation - non-conforming code behavior is up to the implementation.  The -stand flag should be used to catch illegal code.  In addition, this is a bit of a corner case.  If this was a common usage we would have had more that 1 other report of this in 35+ years (there was just 1 other issue on this according to my bug database search).  that one was closed as 'will not fix'.

 

Similarly, based on feedback from my development team, I closed this issue as 'will not fix'.  This is a corner case.  And -stand should be used during development or initial porting to catch potential code issues.  The extension is to allow expressions like this:

10**-2

10**+2

which are allowed and do give "correct" results.  It's when you then add additional operators and values where results that "correct results" no longer apply.  We do not want to penalize codes using the extension for simple cases to accommodate the corner cases such as yours:  10**+2 * 2.  Simply not seen frequent enough to warrant change in behavior.

Issue is closed as 'will not fix'. Recommendation is to use -stand option and validate that codes conform to the Standard and do not rely on vendor extensions. 

 

 

JohnNichols
Colaborador valorado III
10.304 Visualizações

There are two answers, depending on how you "nominally" allow for the missing brackets.  As this is a pure math error, then both answers are correct in terms of getting an answer, otherwise signal an error.  IFX gives answer 2 assuming (-2*2) - one must assume that there are many hundreds of millions of errors like this in all the old Fortran code that people just miss.  

I see a similar thing in the beam theory equations, Harrison (72) provides the complete equations for 2D - they are never taught, three Canadian engineers who only published one paper did the 3D ones, these are not implemented in any commercial code.  But they become important as you seek to match frequency response data. 

So errors abound.  

The problem is the reality that the coder did not follow high school math procedures or they should use LISP where this cannot occur easily. 

JohnNichols_0-1755813065643.jpeg

It is the same as saying, do not sit in the chairs in a thunder storm, someone will. 

 

GaborToth
Novato
10.270 Visualizações

Just today, I fixed a code that was happily committed into one of the models that is part our 1-million line Space Weather Modeling Framwork:  https://github.com/dpawlows/MGITM/commit/494a2aa84a6313baeb4ac1eedf8da8dbc8a255e4)

The code looks like this (there were 2 similar lines, I show one of them):

rtCOP_e = 4.82e-6*te**-0.55*1.0e-6

that is now replaced with
rtCOP_e = 4.82e-6*te**(-0.55)*1.0e-6

The developer, who uses gfortran and ifort, did not see any error messages, and did not know that the two compilers will give different results. I noticed the error because we do nightly tests with several compilers, including nagfor, which immediately refused to compile this. I fixed a similar error a couple of months ago, committed by another person into another model. That's when I learned that ifort does this amazing evaluation.

Did I file a bug report to Intel (or gfortran)? No, because nagfor did find the error, and I fixed it. Do I think that the Intel compiler evaluating this as

rtCOP_e = 4.82e-6*te**(-0.55*1.0e-6)

is correct? No!!! Whoever implemented this Intel extension had no idea about mathematics, and should have been prohibited from working on a compiler that supposed to produce mathematically correct results.

So your choice of just letting this go on, is 

1. Will hurt people who assume that this "extension" works in a mathematically correct way.

2. Will hurt the reputation of your compiler. 

The argument about backward compatibility or the use of -stand flag is lame at best. Here is the result with the -stand flag:

ifort -stand negative_exponent.f90
negative_exponent.f90(2): warning #8810: Consecutive operators are an extension to the Fortran 2008 standard.
<pfe26:~/Bug>a.out
10.0**-2 * 2= 9.9999997E-05

So the warning is about the **-2 and there is nothing said about the following multiplication. The user will assume that the extension works as a normal mathematically educated person would evaluate it. The code still compiled.  And it produced a completely incorrect value. So how did the -stand help?

There are potentially useful extensions, like the isnan() function understood by both gfortran and ifort. Now it is obsolete, because there is the is_nan_ieee() function, but before that this extension was very useful. I compiled the 1-line code "write(*,*) 'Is 1.0 a Nan?', isnan(1.0)" and it does this:

<pfe26:~/Bug>ifort -stand isnan.f90
isnan.f90(2): warning #7416: Fortran 2008 does not allow this intrinsic procedure. [ISNAN]
<pfe26:~/Bug>a.out
Is 1.0 a Nan? F

So I got a warning, but the code gives the expected result. Would it be OK, if isnan(-1.0) would return true? Just because it is an extension and the original compiler developer did not believe in negative numbers?

I hope you get the point and will actually fix the compiler. And if you feel like preserving the incorrect behavior has some value, please add a flag like -MathematicallyIncorrectResults so the user understands the implications.

 

PeteRiley
Novato
10.122 Visualizações

I’d just like to add a caution on the “corner case” argument. The fact that only one or two bug reports exist over decades doesn’t necessarily mean the issue is rare in practice. It could simply reflect a reporting bias - plenty of legacy Fortran codes may be producing incorrect results without their developers realising it, since outputs often go unchecked unless they trigger an obvious failure.

This matters because Fortran is not just an academic language; it remains at the core of mission-critical simulations in aerospace, nuclear energy, and weather/space forecasting. NASA missions, the aviation industry, and even nuclear reactor simulations continue to rely heavily on Fortran. In those contexts, seemingly “rare” conditions can have catastrophic consequences (remember the Ariane 5 failure?).

That’s why dismissing this as “not worth fixing” carries real risk. Even if the problem is indeed uncommon, the cost of being wrong is disproportionately high compared to the effort required to address it.

JohnNichols
Colaborador valorado III
9.649 Visualizações
rtCOP_e = 4.82e-6*te**-0.55*1.0e-6

I would avoid this form of equation as it is easy to get the numbers wrong. mecej4, who has not posted since December, which is a huge loss, taught me to use a base module and put all the standard numbers in the base module and this helps to minimize errors. 

!---------------------------------------------------------------------------------------------------------------------------
!
!   Four modules are called from the main program.
!   Base holds the underlying FORTRAN elements such as dp etc.
!   Subroutines
!                   OpenFiles (i,j,k,l,m)
!                   LineBlank(sw)
!                   Line(sw)
!                   Timingline(sw)
!
!---------------------------------------------------------------------------------------------------------------------------

Module Base

INTEGER, PARAMETER :: dp = selected_real_kind(15, 307)

INTEGER, PARAMETER :: sw = 2                    !   Output file
INTEGER, PARAMETER :: srA = 15                  !   output.txt file
INTEGER, PARAMETER :: st = 14
INTEGER, PARAMETER :: sCAD = 12
INTEGER, PARAMETER :: sa = 3                    !   Output file
INTEGER, PARAMETER :: smWrite = 4
INTEGER, PARAMETER :: si = 1
Integer, parameter :: slog = 9                  !   Log file
Integer, parameter :: nta = 200                  !   Log file
Integer, parameter :: outNode = 63                  !   Log file
Integer, parameter :: inNode = 0                  !   Log file
integer, parameter :: nt1 = 2000
integer, parameter :: mt1 = 2000        !   Number of members
integer, parameter :: mn1 = 2
integer, parameter :: ml1 = 3

REAL (KIND=dp), PARAMETER :: gr = 9.806_DP, pi = 3.14159265_DP  !   Standard parameters
REAL (KIND=dp), PARAMETER :: delta = 0.0001_DP                !   Error number of checking for zero
REAL (KIND=dp), PARAMETER :: ZERO = 0.0_DP
REAL (KIND=dp), PARAMETER :: ONE = 1.0_DP

 

JohnNichols
Colaborador valorado III
9.648 Visualizações
rtCOP_e = 4.82e-6*te**-0.55*1.0e-6
var1 = 4.82e-6
var2 = -0.55
var3 = 1.0/1000000.0
rtCOP_e = var1*var3*te**var2

Much easier to understand. 

andrew_4619
Colaborador honorário III
9.610 Visualizações

An aside really but in your Base module pi = acos(-1.0_DP)  would be better as it gives PI to the DP precision (17sf)  and  not to the number of significant figures you happened to type in.

GaborToth
Novato
9.304 Visualizações

Since I am a beginner, according to this forum, I will refrain from commenting on all the great advice I got about defining constants as Var1, Var2, Var3 and defining pi as a function. Instead I will focus on the actual issue, which has been _correctly_ raised by many people, and has been _completely_ignored_and_misunderstood_ by the Intel compiler team.

The issue is the following: there are N  ~10,000  lines of Fortran code with expressions like this:

a**-b * c

a**+b * c

a**-b / c

a**+b / c

Out of N occurrences, there are M << N lines (~100), where the programmer intended this to be evaluated as 

a**(-b*c)

a**(+b*c)

a**(-b / c)

a**(+b/c)

There are also L >> N lines of code where the signed exponent occurs without a following multiplication or division. These lines are interpreted in the mathematically correct manner and consistent with gfortran and other compilers. 

Now let's look at the following actions:

1. Let's do nothing, because Intel has documented this 20 years ago, and it is the fault of the programmer not to read the great documentation we have produced. 

2. Let's issue an error for every occurrence of **- and **+ (and while at it /- and /+)

3. Let's issue an error for every occurrence of **-b * c, **+b *c,  **-b * c, **+b/c, **-b/c, /-b*c, /+b*c, /-b/c, /+b/c

Let's look at consequences:

Action 1 will result in N - M lines of code contain an undiscovered bug. Since the -stand option does not reveal _anything_ about the actual problem, even if somehow the word would spread that this flag to be used (it does not), it will _not_ change anything.

Action 2 will result in L lines of code stop compiling. L-N>>N lines are perfectly fine, so if the user gets the option to suppress the error, they will, and we end up again with N-M lines of code with undiscovered bugs.

Action 3 will show a potential error for N lines of code with a _proper_error_message_. The developers will then decide if they truly want the result documented by Intel, or if they prefer to get the result taught in high school. Now the result is that we _discover_ N-M bugs, while having a few people who really read the Intel document, and really wanted to write a code that would only work with Intel and definitely fail with every other compiler to add parentheses. Yes, that's the big deal. They have to add parentheses around the exponent, and as a result it will actually work with other compilers. How bad is that?

So your decision of doing nothing results in maintaining 1000s of bugs, and your justification for it is to avoid annoying about 10 people in the world who used the extension as you defined it at the expense of a non-portable code, and that's what they _really_ want. 

So please spend some time on this and ask yourself: are you in the business of creating high quality compilers that behave as people would expect? Or are you making sure that people don't notice that their codes have bugs?

Best regards,

A beginner

 

 

mecej4O
Novato
8.443 Visualizações

"Since I am a beginner, according to this forum, ..."

Please ignore the label that the forum software assigns to you. If a forum member loses the forum password, wishes to use a different email, etc., and creates a new Intel Forum account, that person will be considered to be a "beginner". I expect to be treated just so tomorrow, since I have been away for over a year, although I had been posting in this forum since 2010, and Intel named me "black-belt" for many years.

andrew_4619
Colaborador honorário III
3.808 Visualizações
mecej4O
Novato
4.044 Visualizações

Even if we all agree that something needs to be fixed, the question "Who's to bell the cat?" remains. Should the fix be the responsibility of the authors of the non-standard-conforming Fortran code, of of the authors of the over-lenient compiler?I am inclined to place the onus on the Fortran code writers. They can modify the code to make it standards-compliant, run test problems with several compilers, and then pay attention to simplifying and bettering the code.

GaborToth
Novato
2.412 Visualizações

The typical reaction when I mention to people that 10.0**-2 * 3 =0.000001 (BTW, the autofill gave 0.03   according to Intel Fortran compilers is "What???" suggesting that more people took high school math than read the Intel manual. But a friend of mine took the trouble and looked into this more deeply. He found that Fortran 77 indeed decided to evaluate  this expression as 10.0 ** (-2*3) and they have carefully documented it. Fortran 90 and onwards eliminated this crazy idea and prohibited multiple consecutive arithmetic operators. Intel, in its infinite wisdom, decided to perpetuate this weird Fortran 77 feature as an extension to their Fortran 90 compiler. Other compiler developers followed common sense, mathematics and what every other programming language does (Python, Perl, R, Matlab) and went with 10.0**(-2) *3. So now Intel, when confronted with being the one and only exception, decided that sure, let's keep doing this. I will keep bringing this up at all meetings about scientific software development as a warning, and it will sure shock people that Intel provides a compiler that defies common sense.

Responder