Interesting discussion:
– Ron
Interesting discussion:
– Ron
I guess I’m curious as to why anyone would type this expression as 10**-2 * 2 instead of 2*10**-2 which works as expected with ifx. Frankly to me this is as much an example of poor programming practice as it is a fault or misinterpretation of the standard. My initial reaction is do they want 1E-4 or 2E-2 as the answer. Thats why I always enclose exponentiations in parens.
That is an interesting discussion at community.intel.com.
If compilers would by default compile standard code according to the standard, and print warnings for nonstandard code, then these things would not happen.
We have a similar bug report in LFortran for 1 + -1
(accepts invalid expression · Issue #7192 · lfortran/lfortran · GitHub), where GFortran apparently gives an error (unlike the case above?).
For the above case LFortran currently compiles it and returns 10.0**-2 * 2= 1.99999996e-02
. I think likely we should just give an error message by default, and users have to use a compiler option to enable this extension (I created a new issue for that at Give an error for `10.0**-2 * 2` · Issue #8444 · lfortran/lfortran · GitHub).
“I guess I’m curious as to why anyone would type this expression as 10**-2 * 2 instead of 2*10**-2”.
The priority oder of mathematical operations are: parenthesis, exponentiation, (multiplication and division), (addition and subtraction).
See: Order of operations - Wikipedia
Therefore, 10.0**(-2) * 2 is: (10.0**(-2))*2 or 2*10.0**(-2) and 10.0**(-2) * 2 should be perfectly valid.
The problem is the missing parenthesis around -2.
You should be careful with these general rules. In mathematics an expression like a/bc, or in most programming languages, a/b times c, would mean: a divided by the product of b and c - so: a/(bc). However, all programming languages I know would calculate it as (a/b) times c.
(As the asterisk is usurped by the text editor and turned into a formatting code, I had to use the word “times”)
10.0**(-2)*2
is perfectly valid Fortran expression. 10.0**-2*2
is not.
According to the rules, **
(the power-op) can only be followed by a mult-operand, which must start with a level-1-expr, which can be an optional defined-unary-op (-
is not, it’s an intrinsic operator) followed by a primary, which cannot start with ‘-’ (but can start with (
and be a parenthesized expression).
This is detailed in section 10.1 Expressions of F2023 Final Draft, with the NOTE2 in section 10.1.3 Precedence of operators explicitly forbidding consecutive numeric operators:
These formation rules do not permit expressions containing two consecutive numeric operators, such as A ** –B or A + –B. However, expressions such as A ** (–B) and A + (–B) are permitted.
An exception is made for user-defined operators, with expressions like
A * .INVERSE. B
or- .INVERSE. (B)
being valid.
I completely agree with you.
The simple reason is that 10**2*2
is parsed as (10**2)*2
, so a programmer might expect 10**-2*2
to be parsed similarly as (10**(-2))*2
. But as explained fairly well in the community.intel.com discussion, and also here, that expectation is incorrect. I’m sure that it did not even occur to the original programmer that the expression was incorrect. If he had gotten an error or warning message the first time he tried to compile the code (which might have been 50 or 60 years ago), this error could have been eliminated immediately.
I remember something similarly odd happened to me in the early 1980s when I first began using parameter statements, a new feature in f77. I changed a data statement from
data a / -3.14159, 3.14159 /
to
data a / -pi, pi /
where pi
had been defined already. That didn’t work because the unary - evidently was not an allowed expression in the latter but was in the former.
@rwmsu
I totally agree. Why would you put that in Fortran code !
Surely just write .02 or 2.e-2
I am sure if I found “10**-2*2” in someone’s Fortran code, I would expect to find worse problems than this, or probably just stop looking.
I remember I’ve seen a code like that (e.g. 2.5 * a**-2 + 3.5 or something like that) in other peopole’s code, so I guess it is not too uncommon (though maybe not good code).
Btw, I’ve tried this code on CompilerExplorer:
implicit none
real :: a
a = 10.0
print *, a**-2 + a**-2
print *, a**-2 / a**-2
print *, a**-2 + 2
end
and the results were like this:
gfortran-15.2 (with extension warnings):
1.99999996E-02
1.00000000
2.00999999
LFortran-0.52.0:
1.99999996e-02
1.00000000e+00
2.00999999e+00
flang-trunk (as of 2025-8-27)
2.E-02
1.
2.01
nvfortran-25.7:
2.0000000E-02
1.000000
2.010000
ifort-2021.11.0:
2.0000000E-02
0.0000000E+00 <-----
2.010000
ifx-2024.0.0:
2.0000000E-02
0.0000000E+00 <-----
2.010000
I agree with the OP (in the linked thread) that it would be nicer to raise an error (if **-
is a syntax error), and if an extension is switched on, it returns the same results as the other compilers (and many other languages) to make code less error-prone. The current situation seems worst, because ifort/ifx gives no warning (by default), while giving “strange” results (even if it is consistent with the internal logics).
FWIW, zsh also gives this result
% echo $(( 10.0**-2 + 10.0**-2 ))
0.02
% echo $(( 10.0**-2 / 10.0**-2 ))
1.
% echo $(( 10.0**-2 + 2.0 ))
2.0099999999999998
Coding “10**-2 * 2
” is very different to “2.5*a**-2
” as a**-2
is a run-time calculation.
Coding “10**-2 * 2
” disagrees with the “kiss”, although I would suggest stupid is an understatement.
Most Fortran compilers would now ;
replace “10**-2 * 2
” with .02
.
replace “2.5*a**-2
” with 2.5 / (a*a)
I was a bit annoyed by the lack of asterisks in this post by JohnCampbell, but here the formatting rules of Discourse take precedence over the computational rules of Fortran. Hence, some of the text appears in italic
I fixed it. @JohnCampbell you have to use backticks ` to format things properly.
It is not just consistent with its internal logic, it is also consistent with some 45+ years of established precedence (including the DEC legacy of that compiler). If you were the project manager for that commercial product, would you break 45+ years of precedence, risking the loss of your customer base? I doubt that I would do that.
I also don’t think I would like the standard to change to make this extension standard, with any of the special-case interpretations. All of the special case interpretations discussed here seem inconsistent to me. The standard has changed in the past a few times to accommodate previously nonstantard behavior, and it often has not worked well in the long run. Implicit save of initialized variables is one such example. So please don’t do that again.
It seems to me like gfortran is doing the right thing here, printing the warning by default and then enabling its legacy extension. The only improvement to this might be to add an option for the programmer to enable the other interpretation.
As a programmer, upon seeing the warning I would immediately fix the code (by adding the necessary parentheses). So for me, that solves the problem from that point on for the rest of eternity. I would never need to worry about compiler options or disabling warning messages thereafter. But I realize that sometimes the programmer doesn’t have control over the source code, so compiler options also play a role in these situations.