2012-06-13 59 views
14
int i = 0, j = 0; 
double nan1 = (double)0/0; 
double nan2 = (double)0/0; 
double nan3 = (double)i/j; 
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2)); 
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0)); 
System.out.println(Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2)); 

輸出:迷惑,對楠的Java

true 
true 
false 

請幫我如何輸出的前兩個和false的最後一個來到true。請告訴我什麼是Double.doubleToRawLongBits()方法的實際工作。

+0

有兩種不同的'NaN'正在生產。一個是「0x7ff8000000000000」,另一個是「0xfff8000000000000」。硬件似乎爲'0/0'提供'0xfff8000000000000'。但編譯器的常量傳播使用的是「0x7ff8000000000000」。除非我忽略了一些東西,這對我來說就像是一個bug。 – Mysticial

+0

如果你爲該方法啓用'strictfp'會怎麼樣? – Joey

+5

此外:»在符合IEEE 754標準的浮點存儲格式中,NaN由NaN特有的特定預定義位模式標識。標誌位無關緊要。«([Wikipedia](http://en.wikipedia.org/wiki/NaN#Encoding)) – Joey

回答

3

請嘗試運行下面的代碼來查看值:

public class Test 
{ 
    public static void main(String[] args){ 
     int i = 0, j = 0; 
     double nan1 = (double)0/0; 
     double nan2 = (double)0/0; 
     double nan3 = (double)i/j; 
     System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits(nan2) + " is " + 
      (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2))); 
     System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits((double)0/0) + " is " + 
      (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0))); 
     System.out.println(Double.doubleToRawLongBits(nan3) + " == "+ Double.doubleToRawLongBits(nan2) + " is " + 
      (Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2))); 
    } 
} 

我的Mac上,它會產生以下的輸出:

9221120237041090560 == 9221120237041090560 is true 
9221120237041090560 == 9221120237041090560 is true 
-2251799813685248 == 9221120237041090560 is false 

這個陷阱在Javadoc文檔的doubleToRawLongBits method

如果參數是NaN,則結果是代表實際NaN值的長整數。與doubleToLongBits方法不同,doubleToRawLongBits不會將編碼NaN的所有位模式摺疊爲單個「規範」NaN值。

+2

這是回答這個問題嗎? – Mysticial

+0

代碼與問題中的代碼相同,相當多餘;但在跟文檔鏈接之後*儘管有一個間接的問題,但回答了這個問題。我編輯了相關部分作爲報價。但我會說,以上所有的東西都只是與答案無關的垃圾。 – Joey

+0

我不認爲這解決了我對這個問題的困惑。 –

1

我認爲Java遵循IEEE 754.在這種情況下,NaN具有多個可能的位表示。你的情況中的兩種表示在「符號」位中不同。標誌位的值似乎沒有被標準定義,通常被忽略。所以這兩個值都是正確的。請參閱http://en.wikipedia.org/wiki/NaN

0

原因是因爲當您將雙變量0除以0時,它將返回NaN,因此該方法在二進制文件中沒有單個標準表示形式,因此它可能會返回NaN的二進制文件,如7F F8 00 00 00 00 00 00或FF F8 00 00 00 00 00 00.

即使在技術上它們代表了相同的東西,即NaN,它在二進制表示方面有所不同。

2

IEEE 754標準允許不同的位模式爲NaN。爲了計算和比較的目的,它們應該都是相同的(即,NaN比較不等於它本身,不是有序的,並且涉及NaN的每個計算本身都是NaN)。用doubleToRawLongBits你可以得到確切的位模式。這也詳述在JLS:

在大多數情況下,Java平臺把一個給定類型的 NaN值雖然摺疊到單個規範值(因此本說明書中去甲 馬利指任意的NaN,彷彿一個規範的值)。但是,版本 1.3 Java平臺引入的方法使編程人員能夠在NaN值之間區分 :Float.floatToRawIntBitsDouble.double- ToRawLongBits方法。對於FloatDouble類感興趣的讀者可以參考 的規格瞭解更多信息。

在你的情況下,籤位是不同的,在這種情況下,我可以引導您到Wikipedia,它總結了簡潔:

在IEEE 754符合標準的浮點存儲格式,NaN是確定通過特定的,預定義的NaN特有的位模式。符號位並不重要。

你的值都是NaN,它們只是用不同的位來表示它。這是IEEE 754允許的,在這種情況下,可能源於編譯器替代Double.NaN進行常數計算,結果爲NaN,而實際硬件給出了不同的結果,正如Mysticial在對該問題的評論中所懷疑的那樣。

+0

Joey編譯器爲NaN值隨機選擇不同的位模式。如果否,那麼爲什麼nan1和nan2的模式相同,但nan3的模式不同。 –