2013-08-19 34 views
1

獲得+ -inf在64位系統上,我用下一個代碼gfortran:爲什麼「-posinf」導致算術溢出?

double precision, parameter :: pinf   = transfer(z'7FF0000000000000',1d0) ! 64 bit 
double precision, parameter :: ninf   = transfer(z'FFF0000000000000',1d0) ! 64 bit 

,而且運作良好。

在32位 我有一個編譯錯誤,只爲NINF(!):

double precision, parameter :: ninf   = transfer(z'FFF0000000000000',1d0 
                      1  
Error: Integer too big for integer kind 8 at (1) 

分配ninf = -pinf不是幫助,並導致編譯算術溢出錯誤:

double precision, parameter :: ninf   = -pinf 
                 1 
Error: Arithmetic overflow at (1) 

我瞭解ieee_arithmetic模塊,但gcc不處理它。

是否有任何多架構方式將常量設置爲正/負無窮?

更新 Gfortran選項-fno-range-check抑制錯誤併成功編譯該代碼。

這並不重要,但我仍然很有趣。 爲什麼gfortran允許+ Infinity的恆定定義,但大聲喊叫與-Infinity完全相同的東西?因爲你是我沒有使用相同的編譯器

回答

1

在這種情況下,gfortran在內部將您的十六進制(「Z」)文字表示爲可用的最大無符號整數大小。由於transfer是一個Fortran內在函數,而Fortran沒有無符號整數,因此gfortran所做的第一件事就是將文字分配給一個帶符號的類型,這會導致您的位模式出現負無窮大。在使用BOZ文字的許多其他情況下,這種情況會發生,我認爲這是gfortran中的一個錯誤。

我認爲這隻顯示在32位系統上,因爲在你的64位系統上,gfortran可能有128位整數類型;一個128位有符號整數不會「溢出」該位模式。

但是,這也是你的代碼不符合Fortran標準的,它說,十六進制文字只能出現內部data陳述或功能intreal,或dble的情況。但是,將dble中的十六進制文字與transfer完全相同。如果gfortran沒有bug,你的程序就可以工作,但是在技術上是不正確的。

不管怎樣,下面的代碼對我的作品在gfortran,我相信它會在某種程度上這是符合標準的,並且避免瞭解決您的問題-fno-range-check

integer, parameter :: i8 = selected_int_kind(13) 
integer, parameter :: r8 = selected_real_kind(12) 
integer(i8), parameter :: foo = int(Z'7FF0000000000000',i8) 
integer(i8), parameter :: bar = ibset(foo,bit_size(foo)-1) 
real(r8), parameter :: posinf = transfer(foo,1._r8) 
real(r8), parameter :: neginf = transfer(bar,1._r8) 
print *, foo, bar 
print *, posinf, neginf 
end 

輸出:

9218868437227405312 -4503599627370496 
        Infinity     -Infinity 

關鍵是首先創建正無窮大模式(因爲它起作用),然後通過簡單地設置符號位(最後一個)來創建負無窮大模式。 ibset內在只適用於整數,因此您必須在這些整數上使用transfer來設置您的實際正/負無窮大。

(我的I8的使用/ R8只是習慣,因爲我已經用編譯器工作,在那裏種參數不等於字節數。他們都是在這種情況下等於8。)

+0

謝謝,它變得更加清晰。我真的認爲沒有辦法通過Fortran標準來完成「乾淨」的工作。這隻帶有十六進制常數的膠帶只是因爲gfortran中支撐ieee-754的泄漏。它一定是hacky。 – Sergei

+0

我用過的其他Fortran編譯器(Cray,IBM,Intel,NAG,PGI)都有'IEEE_ARITHMETIC'模塊,這使得在運行時更容易設置Infinity或NaN。但是,該模塊中的幾乎所有內容在運行時只有*可用*,因此如果不使用十六進制文字,您仍然無法設置「參數」常量。 –

1

(我使用g95與編譯器選項-i4集的32位整數,和一個解決方法(如果你是堅定的關於使用transfer爲目的),我發現是指定整數參數作爲參數,如下所示:

注意:使用我的編譯器,我可以直接將數字賦給參數,我不確定它是否與您的參數相同,當你不真正處理常量時 - 例如,如果你在使用浮點數做一些花哨的事情,並且需要對代表的表示進行真正的控制,那麼你肯定只能真正使用傳遞函數。

請注意變量pdirectndirect

program main 
integer(8), parameter :: pinfx= z'7FF0000000000000' 
integer(8), parameter :: ninfx= z'FFF0000000000000' 
double precision, parameter :: pinf = transfer(pinfx, 1d0) 
double precision, parameter :: ninf = transfer(ninfx, 1d0) 

double precision, parameter :: pdirect = z'7FF0000000000000' 
double precision, parameter :: ndirect = z'7FF0000000000000' 


write (*,*) 'PINFX ', pinfx 
write (*,*) 'NINFX ', ninfx 
write (*,*) 'PINF ', pinf 
write (*,*) 'NINF ', ninf 
write (*,*) 'PDIRECT', pdirect 
write (*,*) 'NDIRECT', ndirect 

end program 

這將產生輸出:

PINFX 9218868437227405312 
NINFX -4503599627370496 
PINF +Inf 
NINF -Inf 
PDIRECT +Inf 
NDIRECT +Inf 

我希望這有助於!

+0

謝謝!我編譯了你的例子,並得到了與問題中相同的錯誤。 gfortran選項'-fno-range-check'抑制了錯誤並編譯了我想要的內容。但我不喜歡這個解決方案。 – Sergei

+0

我還是不明白爲什麼gfortran中積極和消極的無窮之間有如此大的差異。 – Sergei

相關問題