2013-04-11 69 views
2

我想编译一个gfortran程序并启用-O3 -ffast-math,因为它提供了很好的性能提升。我很困惑,gfortran的isnan()抓住了一些NaN,但不是全部。阅读是否有可能让isnan()在gfortran -O3 -ffast-math中工作?

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?

后,我的印象是,人们能够通过位摆弄与快速数学甚至启用了C到检查NaN的。然而,这让我为难,因为快速的数学

可能导致不正确的输出依赖于数学函数的具体实现的 IEEE或ISO的规则/规范的程序。

根据gcc 4.7.2的手册页。那么,如果数字不是按照IEEE标准来表示的,那么您怎么知道哪个位需要检查?如果你知道它,你将如何在Fortran 95/03/08中实现它?

不要打扰张贴(x \= x)或依赖于IEEE规则的模拟解决方案。他们给出了与isnan()相同的结果。我也知道-ffpe-trap=invalid,zero,overflow,但不想停止该程序。如果有帮助,我的操作系统是64位LinuxMint 14.如果在Fortran中不可行,防水C解决方案也会很好。

+1

在支持的编译器中可以通过使用适当的内在模块强制编译器遵守IEEE规则。但是,gfortran不支持这一点。你必须忍受快速数学在这方面不安全的事实。 – 2013-04-11 11:18:01

+1

当你打开'快速数学'时,你有希望编译器可以自由假装NaN不存在。这意味着通常产生NaN的计算可能不会,并且编译器可以优化任何检查NaN的代码(因为您承诺它们不存在!),这使得'isnan'本质上是无用的。你的问题相当于晚上蒙着眼睛在弯弯曲曲的山路上超速行驶,并担心你的尾灯失灵。 – 2013-04-18 15:57:01

回答

3

首先我会指出gfortran 4.9支持IEEE_arithmetic模块但是,我不能依靠gfortran 4.9,它太新鲜了。

我其实在实践中使用的是支票x/=x移动到其未经-ffast-math和不带链接时优化编译程序:

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 

它是在一个单独的文件,然后不-Ofast编译,--ffast-math且没有-flto。请注意,内联不足会导致严重的性能下降。

+0

你有没有检查过它实际上是否_always_与来自用'-fast-math'编译的模块的数字一起工作?如果这样你能解释为什么?我认为重要的信息本身并不在检查过程中。 – bijancn 2014-11-27 11:09:19

+0

@bijancn不,重点在检查程序中。 '-fast-math'简单地将检查优化为false。这很简单。 – 2014-11-27 11:48:23

+0

我明白了。为你+1! – bijancn 2014-11-27 14:03:56

1

我在gfortran-4.7中遇到了同样的问题,并开始尝试一些表达式。

check = ((x*2d0==x).AND.(
     (x<-epsilon(1.d0)).OR. 
     (x>+epsilon(1.d0)))) 

我检查只有双精度值和-02 -ffast,数学,-O3 -ffast-数学选项:对于我的测试情况下,如果x为NaN这一回真。请注意,这返回.false。如果使用没有优化标志,因此你将不得不将它与

isnan(x) .OR. check 
+0

如果你想支持多个编译器和版本以及精度类型,那么这是一个有趣的黑客攻击,但并不是真正的解决方案:)。 – bijancn 2014-11-27 11:11:00