2013-04-11 53 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