比较Double.NaN和自己
我被困在试图找出为什么这两个操作返回不同的值:
-
Double.NaN == Double.NaN
返回false
-
Double.NaN.Equals(Double.NaN)
返回true
我有第一部分的答案 ,但不是第二部分,而不是“为什么这两个比较返回不同的值”
这个差别的原因很简单,如果不是很明显的话。
如果您使用相等运算符==
,那么您使用IEEEtesting的相等性。
如果你使用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.GetHashCode()
广泛地使用object.GetHashCode()
object.Equals(object)
和object.GetHashCode()
并依靠其行为的保证。
在Double.Equals
备注部分的Double.Equals
,你会发现:
如果通过调用Equals方法testing两个Double.NaN值是否相等,则该方法返回true。 但是,如果使用相等运算符testing两个NaN值是否相等,则运算符返回false。 当你想确定Double的值是不是一个数(NaN)时,另一种方法是调用IsNaN方法。
那么, Oded的回答很好,但我想说点什么。
当我反编译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`.
所以基本上它可以return ((obj == this) || true
这是等价的
return ((obj == this)
是true
。
如果你检查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
第二个返回true,因为NaN
相等是在重载的equals
方法中显式实现的。
来自msdn double.equals :
如果通过调用Equals方法testing两个Double.NaN值是否相等,则该方法返回true。 但是,如果使用相等运算符testing两个NaN值是否相等,则运算符返回false。 当你想确定Double的值是不是一个数(NaN)时,另一种方法是调用IsNaN方法。
这是完全符合IEC 60559:1989
;
根据IEC 60559:1989,有两个NaN值的浮点数永远不会相等。但是根据System.Object :: Equals方法的规范,可以重写这个方法来提供值相等的语义。 由于System.ValueType通过使用Reflection来提供此function,因此Object.Equals的说明特别指出值types应考虑覆盖默认的ValueType实现以获得性能提升。 实际上,从查看System.ValueType :: Equals(SSCLI中的clr \ src \ BCL \ System \ ValueType.cs的第36行)的源代码,甚至还有来自CLR Perf团队对System.ValueType ::等于不快。
请参阅: http : //blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx