2013-01-22 39 views
36

我被困試圖找出爲什麼這兩個操作返回不同的值:Double.NaN與自身比較

  1. Double.NaN == Double.NaN返回false
  2. Double.NaN.Equals(Double.NaN)返回true

我有answer到第一部分但不是第二部分,而不是「爲什麼這兩個比較返回不同的值」

+2

可能是一個愚蠢的評論,但我會說,情況1,你是比較值。在案例2中,您正在比較參考。 – jbl

+4

@jbl不,你在比較兩種情況下的值 - 'double's不是引用,因爲['System.Double.Equals'](http://msdn.microsoft.com/ en-us/library/ya2zha7s.aspx)被重載。 –

+0

@spender OMFG我應該更好地閱讀這個問題!謝謝! –

回答

30

如果不明顯,差異的原因很簡單。

如果您使用相等運算符==,那麼您使用的是IEEE測試的相等性。

如果您使用的是Equals(object)方法,那麼您必須維護object.Equals(object)的合同。實施此方法(和相應的GetHashCode方法)時,您必須維護該合同,這與IEEE行爲不同。

如果Equals合同沒有被維護,那麼哈希表的行爲就會中斷。

var map = new Dictionary<double,string>(); 
map[double.NaN] = "NaN"; 
var s = map[double.NaN]; 

如果!double.NaN.Equals(double.NaN),你永遠不會從字典中得到你的價值!

如果前面一句沒有意義,那麼理解散列的機制(在Dictionary<T,U>HashSet<T>等使用)同時使用object.Equals(object)object.GetHashCode()方法廣泛,並且依靠自己的行爲的保證。

+1

啊。最後。 :-)(我非常希望在這裏爲索賠找到適當的參考,但我相信這是正確的答案(合同部分肯定是),所以+1)。 –

+1

是的,我應該指出,我沒有參考。這只是對我有意義的唯一原因。 –

+1

+1。你能否提供一個參考IEEE測試平等的參考?我找不到它的任何地方 – GETah

9

在的Double.Equals註釋部分的最底部,你會發現:

如果兩個Double.NaN值通過調用Equals方法相等測試,該方法返回true。但是,如果使用相等運算符測試兩個NaN值是否相等,則運算符返回false。當您想要確定Double的值是否不是數字(NaN)時,另一種方法是調用IsNaN方法。

+2

我不知道是否有一個原因超出_文檔說so_ :) –

+0

感謝您的快速答案。你知道爲什麼這種差異? – GETah

+4

這不回答問題的「爲什麼」部分。 – ken2k

3

如果您檢查Double.NaN;

// Summary: 
    //  Represents a value that is not a number (NaN). This field is constant. 
    public const double NaN = 0.0/0.0; 

第一個返回false,因爲NaN不代表任何數字。

方法或操作符返回NaN當操作的結果是 未定義。例如,零被零除的結果是NaN

NaN平等在重載equals方法明確地實現第二個返回true。

msdn double.equals

如果兩個Double.NaN值通過調用的Equals 方法的相等測試,該方法返回true。但是,如果使用相等運算符對兩個NaN值進行 的相等性檢驗,則運算符返回 false。當你想確定Double的值是不是 的數字(NaN)時,另一種方法是調用IsNaN方法。

這是完成delibaretly以符合IEC 60559:1989;

根據IEC 60559:1989,與 的NaN的值的兩個浮點數是從未equal.However,根據本說明書的System.Object的:: Equals已 方法,這是期望的是覆蓋此方法以提供值爲 的平等語義。由於System.ValueType通過使用Reflection來提供此功能,因此Object.Equals的說明特別指出,值類型應該考慮 覆蓋默認的ValueType實現以獲得增加的性能 。事實上,通過查看 System.ValueType :: Equals(clr \ src \ BCL \ System \ ValueType的第36行)的來源。cs 在SSCLI中),甚至有來自CLR Perf團隊的評論意見,因爲System.ValueType :: Equals不是很快的 效應。

參考:http://blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx

+2

問題是**爲什麼**這兩種方法產生不同的結果。你沒有回答。 –

+0

我確實相信我已經回答了; NaN沒有定義,不代表任何數字,它是未定義的。談論平等是不可能的;但equals方法定義了兩個NaN值之間的等式。 – daryal

+2

*爲什麼*是這樣定義的'Equals'?你只是[乞求問題](https://en.wikipedia.org/wiki/Begging_the_question)。 –

3

好,Oded's answer是偉大的,但我想說的東西;

當我反編譯Double.Equals()方法時,看起來像這樣;

public bool Equals(double obj) 
{ 
    return ((obj == this) || (IsNaN(obj) && IsNaN(this))); 
} 

所以,因爲我們有這個= Double.NaN的obj = Double.NaN

(IsNaN(obj)) and (IsNaN(this)) returns `true`. 

所以basicly很可能return ((obj == this) || true

這等同放着清單

return ((obj == this)true

+3

+1。我現在越來越困惑:p – GETah

+1

而且這只是乞討的問題。我們已經知道* Double.Equals對NaN有特殊的處理,問題是* why。 –

+0

@KonradRudolph,我解釋了爲什麼在我的答案。這是因爲必須維護語義合約。 –