比较Double.NaN与自身

时间:2013-01-22 12:45:50

标签: c# .net double nan

我很难找到为什么这两个操作会返回不同的值:

  1. Double.NaN == Double.NaN返回false
  2. Double.NaN.Equals(Double.NaN)返回true
  3. 我有answer到第一部分而不是第二部分而不是"为什么这两个比较会返回不同的值"

4 个答案:

答案 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相等。

来自msdn double.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