所以如果反编译.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;
}
我的 friend 告诉我==
的实现可能是return !IsNan(this) && this.InnerEquals(other);
但是 NaN 的 afaik 实现是在处理器本身的硬件层上硬编码的。而且我们不应该单独处理 NaN
的情况。
还有一个问题。为什么这么蠢?
bool b1 = (double.NaN == double.NaN); // false
bool b2 = double.NaN.Equals(double.NaN); //true
我知道一个实现
[__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;
}
但不知道为什么
最佳答案
在 IEEE754 中,NaN 值被编码为具有 0
或 1
的符号位以及所有 1
位的指数部分。小数部分中的值是无关紧要的,只要它们不都是 0
位(如果是,则它是无穷大之一而不是 NaN)。
因此考虑 32 位单精度 float :
s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
x 11111111 ???????????????????????
我在上面的小数位中使用了 m
(尾数),以免与十六进制数字 f
混淆。
如果不是所有 ?
位都为零,则它是 NaN 编码之一。如果将其转换为 32 位长,则检查二进制文件很简单:
x 11111111 00000000000000000000000
并且,如果它大于正变体或小于负变体,那就是 NaN 编码之一。
&
操作忽略符号,因为已签名的 long.MaxValue
将为 2^63 - 1
(假设它是 64 位的)这样操作只会将最高有效位强制为 0
。
魔法值由 0
符号位构成,它是所有 1
位的指数(对于 double ,有 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
给出 0x7ff0000000000000
或 9218868437227405312
。
关于c# - 为什么 double.IsNaN 有如此奇怪的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19832493/