问题
I would like to compile a program with gfortran and -O3 -ffast-math
enabled, since it gives a nice performance boost. I was rather confused, that gfortran's isnan()
catched some NaN's but not all of them. After reading
Checking if a double (or float) is NaN in C++
how do I make a portable isnan/isinf function
Negative NaN is not a NaN?
I am under the impression that people are able to check for NaN's in C via bit-fiddling even with fast-math enabled. However, this puzzles me since fast-math
can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions.
According to the man page of gcc 4.7.2. So how do you know which bit to check, if the numbers are not represented according to IEEE standard? And if you know it, how would you implement it in Fortran 95/03/08?
Don't bother to post (x \= x)
or simlar solutions which depend on IEEE rules. They give the same result as isnan()
. I am also aware of -ffpe-trap=invalid,zero,overflow
, but don't want to stop the program. If it helps, my OS is 64-bit LinuxMint 14. If it is not possible in Fortran, a waterproof C solution would also be nice.
回答1:
First I would point out that gfortran 4.9 supports the IEEE_arithmetic module. However, I cannot depend on gfortran 4.9, it is too fresh.
What I actually use in practice is to move the check x/=x
to a procedure which is compiled without -ffast-math
and without link time optimizations:
module ieee_arithmetic
!poor man's replacement for the intrinsic module
!do not use if the compiler supports the F2003 version
!make sure not to use fast math optimizations
use iso_fortran_env
!common extension isnan may actually fail with optimizations above
! intrinsic isnan
interface ieee_is_nan
module procedure ieee_is_nan_real32
module procedure ieee_is_nan_real64
end interface
contains
logical function ieee_is_nan_real32(x) result(res)
real(real32), intent(in) :: x
res = x /= x
end function
logical elemental function ieee_is_nan_real64(x) result(res)
real(real64), intent(in) :: x
res = x /= x
end function
end module
It is in a separate file, which is then compiled without -Ofast
, --ffast-math
and without -flto
. Beware the lack of inlining can case serious performance decrease.
回答2:
I was facing the same problem in gfortran-4.7 and started to experiment with some expressions. For my Test Cases this one returned true if x is a NaN:
check = ((x*2d0==x).AND.(
(x<-epsilon(1.d0)).OR.
(x>+epsilon(1.d0))))
I've checked only double precision values and -O2 -ffast-math, -O3 -ffast-math options. Note that this returns .false. if using no optimization flags, thus you would have to combine it with
isnan(x) .OR. check
来源:https://stackoverflow.com/questions/15944614/is-it-possible-to-make-isnan-work-in-gfortran-o3-ffast-math