为什么加倍.IsNaN有如此奇怪的实现

时间:2013-11-07 09:41:02

标签: c# .net floating-point double ieee-754

因此,如果反编译.net源代码,您可以找到此代码

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SecuritySafeCritical]
[__DynamicallyInvokable]
public static unsafe bool IsNaN(double d)
{
  return (ulong) (*(long*) &d & long.MaxValue) > 9218868437227405312UL;
}

所以根据IEEE754 NaN != NaN

所以问题很简单:为什么它看起来不像

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SecuritySafeCritical]
[__DynamicallyInvokable]
public static unsafe bool IsNaN(double d)
{
  return d != d;
}

我的朋友告诉我==的实施可能是return !IsNan(this) && this.InnerEquals(other);

但NaN的实现在硬件层硬编码,在处理器本身。我们不应单独处理NaN个案。


还有一个问题。为什么这么愚蠢?

bool b1 = double.NaN == double.NaN); // false
bool b2 = double.NaN.Equals(double.NaN); //true

http://ideone.com/ZSRYz1

我知道一个实现

[__DynamicallyInvokable]
public override bool Equals(object obj)
{
  if (!(obj is double))
    return false;
  double d = (double) obj;
  if (d == this)
    return true;
  if (double.IsNaN(d))
    return double.IsNaN(this);
  else
    return false;
}

但不知道为什么

2 个答案:

答案 0 :(得分:9)

在IEEE754中,编码的NaN值具有符号位01以及所有1位的指数部分。分数部分中的值是无关紧要的,只要它们不是全部0位(如果它们是,它是无穷大而不是NaN之一)。

因此考虑32位单精度浮点数:

s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
x 11111111 ???????????????????????

我已经使用m(用于尾数)作为上面的分数位,以免将它与十六进制数字f混淆。

如果没有那些?位的所有为零,则它是NaN编码之一。如果将其转换为32位长,则检查二进制文件是一件简单的事情:

x 11111111 00000000000000000000000

并且,如果它大于正变量或小于负变量,则是NaN编码之一。

忽略了由&操作完成的符号,因为签名的long.MaxValue将是2^63 - 1(假设它是64位),因此操作只会强制执行重要的一点0

神奇值由0符号位构成,是所有1位的指数(对于双精度,其中有11位,以及分数中的所有0位因此二进制:

seee eeee eeee mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
0111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

提供0x7ff00000000000009218868437227405312

答案 1 :(得分:4)

很难确定不是实现者,但我的猜测是设计师考虑发信号NaN(SNAN)。如果异常未被屏蔽,那么在SNAN上测试相等性将引发硬件浮点异常。