2016-06-17 70 views
9

所以我最近開始熱愛語言kotlin。今天,在比較雙打的同時,我遇到了不可避免的NaN比較Kotlin中的NaN

fun main(args: Array<String>) { 
    val nan = Double.NaN 
    println("1: " + (nan == nan)) 
    println("2: " + (nan == (nan as Number))) 
    println("3: " + ((nan as Number) == nan)) 
} 

NB:(DoubleNumber亞型)

運行上面的代碼得到:

1: false 
2: true 
3: true 

我明白comparing在Java NaN返回false ,所以我期望false爲所有表達式。

這種行爲如何解釋? 它背後的基本原理是什麼?

回答

8

這是因爲(2)(3)編譯拳擊原始然後Double.equals檢查:在JVM,原始double不能相比盒裝之一。

Double.equals,反過來,通過比較兩個Double S的doubleToLongBits(...)檢查平等,後者有一個保證

如果參數是NaN,那麼結果是0x7ff8000000000000L

因此,返回的兩位NaN的位相等,並且規則NaN != NaN在此處被忽略。

而且,@miensol提到,有這種平等檢查的另一個後果:+0-0根據==檢查和不檢查equals是相等的。在Java中

等效代碼如下:

double nan = Double.NaN; 
System.out.println("1: " + (nan == nan)) //false 
System.out.println("2: " + ((Double) nan).equals(((Number) nan))) 
System.out.println("3: " + ((Number) nan).equals(nan)); 

最後兩行打電話Double.equals,比較doubleToLongBits(...)

+2

我認爲,如果你提到從[文件]以下行(https://docs.oracle.com/javase/7/docs/api/java/lang/你的答案是更完整DoubleToLongBits「的double.html#doubleToLongBits(double)):**除了所有NaN值被摺疊爲單個」規範「NaN值**。否則,你可能會認爲兩個不同的'NaN'會與該函數的false相比較。 – nfs

+0

@nrohwer,謝謝你的評論,更新了答案。 – hotkey

7

第一個比較等同於Java的:

double left = Double.NaN; 
double right = Double.NaN; 
boolean result = left == right; 

正如你可以read in this answer這是標化和記錄的行爲。

第二&第三次比較等同於:

Double left = Double.valueOf(Double.NaN); 
Number right = Double.valueOf(Double.NaN); 
boolean result = left.equals(right); 

其中採用Double.equals

注意,在大多數情況下,爲class Doubled1d2, 的價值兩個實例d1.equals(d2)當且僅當d1.doubleValue() == d2.doubleValue()也具有真值。但是,有兩個例外 :

  • 如果d1d2都表示Double.NaN,然後等號 方法返回true,即使Double.NaN==Double.NaN具有價值 false

  • 如果d1表示+0.0d2表示-0.0,或者反之亦然, 相等測試具有值false,即使+0.0==-0.0具有 值true