我很难找到为什么这两个操作会返回不同的值:
Double.NaN == Double.NaN
返回false
Double.NaN.Equals(Double.NaN)
返回true
我有answer到第一部分而不是第二部分而不是"为什么这两个比较会返回不同的值"
答案 0 :(得分: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 :(得分:9)
在Double.Equals
的备注部分的最底部,您会发现:
如果通过调用Equals方法测试两个Double.NaN值的相等性,则该方法返回true。但是,如果使用等于运算符测试两个NaN值的相等性,则运算符返回false。当您想确定Double的值是否不是数字(NaN)时,另一种方法是调用IsNaN方法。
答案 2 :(得分: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
第二个返回true,因为在重载的NaN
方法中显式实现了equals
相等。
如果通过调用Equals来测试两个Double.NaN值的相等性 方法,该方法返回true。但是,如果测试了两个NaN值 为了通过使用相等运算符进行相等,运算符返回 假。当您想确定Double的值是否不是时 一个数字(NaN),另一种方法是调用IsNaN方法。
这样做是为了符合IEC 60559:1989
;
根据IEC 60559:1989,两个浮点数的值为 NaN永远不会相等。但是,根据System.Object :: Equals的规范 方法,希望覆盖此方法以提供值 平等语义。由于System.ValueType提供了此功能 功能通过使用Reflection,描述 Object.Equals特别指出值类型应该考虑 覆盖默认的ValueType实现以获得性能 增加。事实上从查看源头 System.ValueType :: Equals(clr \ src \ BCL \ System \ ValueType.cs的第36行 在SSCLI中,甚至还有来自CLR Perf团队的评论 System.ValueType :: Equals的效果不快。
请参阅:http://blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx
答案 3 :(得分:3)
嗯,Oded's answer很棒,但我想说些什么;
当我反编译Double.Equals()
方法时,它似乎就是这样;
public bool Equals(double obj)
{
return ((obj == this) || (IsNaN(obj) && IsNaN(this)));
}
因为我们有 this = Double.NaN 和 obj = Double.NaN
(IsNaN(obj)) and (IsNaN(this)) returns `true`.
基本上它可以return ((obj == this) || true
与
等价 return ((obj == this)
是true
。