40

我一直试图找出这两个操作返回不同值的原因:

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

我有第一部分的答案,但没有第二部分的答案,也没有“为什么这两个比较返回不同的值”的答案

4

4 回答 4

34

造成这种差异的原因很简单,即使不是很明显。

如果您使用相等运算符==,那么您正在使用 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()方法,并依赖于对其行为的保证。

于 2013-01-22T13:00:18.330 回答
9

在备注部分的最底部Double.Equals,您会发现:

如果通过调用 Equals 方法测试两个 Double.NaN 值是否相等,则该方法返回 true。但是,如果使用相等运算符测试两个 NaN 值是否相等,则运算符返回 false。当您想要确定 Double 的值是否不是数字 (NaN) 时,另一种方法是调用 IsNaN 方法。

于 2013-01-22T12:50:04.693 回答
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 值是否相等,则运算符返回 false。当您想要确定 Double 的值是否不是数字 (NaN) 时,另一种方法是调用 IsNaN 方法。

故意这样做是为了符合IEC 60559:1989;

根据 IEC 60559:1989,具有 NaN 值的两个浮点数永远不会相等。但是,根据 System.Object::Equals 方法的规范,最好覆盖此方法以提供值相等语义。由于 System.ValueType 通过使用反射来提供此功能,因此 Object.Equals 的描述明确指出,值类型应考虑覆盖默认的 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

于 2013-01-22T12:52:45.437 回答
3

好吧,Oded 的回答很好,但我想说点什么;

当我反编译Double.Equals()方法时,它看起来像这样;

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

所以既然我们有this = Double.NaNobj = Double.NaN

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

所以基本上可以return ((obj == this) || true

这相当于

return ((obj == this)true

于 2013-01-22T12:59:15.350 回答