This came up in https://github.com/JuliaLang/julia/issues/24568, specifically this comment https://github.com/JuliaLang/julia/issues/24568#issuecomment-345004303. The question was, just looking at a code
float X, XMin, Y;
if (X < XMin)
{
Y= 1 / (XMin - X);
XMin= X;
}
can you see how this code might possibly raise an error under -ffast-math
?
Here is a simple example to test this behavior:
program divison_test
implicit none
integer, parameter :: dp = kind(0.d0)
real(dp) :: x, y
x = 5e-324_dp
y = 1 / x
print *, x, y, x > 0
end
This gives:
$ gfortran b.f90 && ./a.out
4.9406564584124654E-324 Infinity T
$ gfortran -ffast-math b.f90 && ./a.out
0.0000000000000000 Infinity F
$ gfortran -O3 -ffast-math b.f90 && ./a.out
0.0000000000000000 Infinity T
In the first case, the condition x>0
evaluated as True, so x
is a positive number, but 1/x
still gave infinity. Btw, this is already a problem — if my computational code gets an infinity like this, and I need to use y
later, it’s pretty much all over, the code will crash. In other words, I want that if
statement to catch this, but it would fail to catch it above.
In the second case, the condition x > 0
evaluated as false, so that’s correct.
However, in the third case, the condition evaluated as true, yet x
is zero, and I got a division by zero basically.
A robust solution around these things is to write the code like this:
program divison_test
implicit none
integer, parameter :: dp = kind(0.d0)
real(dp) :: x, y
x = 5e-324_dp
y = 1 / x
print *, x, y, abs(x) > 1e-12_dp
end
Then no matter how it is compiled, the x>0
condition always evaluates as false, and thus I never get any division by zero or infinity if I put this into an if statement:
$ gfortran -O3 -ffast-math d.f90 && ./a.out
0.0000000000000000 Infinity F
$ gfortran -ffast-math d.f90 && ./a.out
0.0000000000000000 Infinity F
$ gfortran d.f90 && ./a.out
4.9406564584124654E-324 Infinity F