.net 正在将Double.NaN与其自身进行比较

nr9pn0ug  于 2022-12-05  发布在  .NET
关注(0)|答案(5)|浏览(103)

我一直在试图找出为什么这两个操作返回不同的值:

  1. Double.NaN == Double.NaN返回false
  2. Double.NaN.Equals(Double.NaN)返回true
    我有answer到第一部分,但没有第二部分,也没有到“为什么这两个比较返回不同的值”
7gcisfzg

7gcisfzg1#

差异的原因很简单,如果不是显而易见的话。
如果使用相等运算符==,则使用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()方法,并依赖于它们行为的保证。

czfnxgou

czfnxgou2#

Double.Equals的备注部分的最底部,您将找到:
如果通过调用Equals方法来测试两个Double.NaN值是否相等,则该方法返回true。但是,如果通过使用相等运算符来测试两个NaN值是否相等,则该运算符返回false。如果要确定Double的值是否不是数字(NaN),另一种方法是调用IsNaN方法。

ego6inou

ego6inou3#

好吧,Oded's answer是伟大的,但我想说的是;
当我反编译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
其相当于
就是true

9lowa7mx

9lowa7mx4#

如果检查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::Equals速度不快进行了注解。
请参阅:http://blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx

b4qexyjb

b4qexyjb5#

我会避免这两种操作中的任何一种。根据Microsoft文档中有关代码分析的使用规则,规则CA 2242(TestforNaN correctly)表示“要修复此规则的冲突并准确确定某个值是否表示System.Double.NaN,使用System.Single.IsNaN或System.Double.IsNaN来测试该值。"。因此,我建议您使用double.IsNaN(double.NaN)&& double.IsNaN(double.NaN),它总是返回true。这个例子虽然没有意义,但却是正确的。我建议你避免比较双精度数是否相等。舍入错误可能导致非常小的差异,但这些差异足以破坏相等性。当比较名为a和b的两个双精度数时,我会使用如下代码:如果(Math.Abs(a-b)〈1 e-20)。也许这没有回答这个问题,但我认为它需要说出来。

相关问题