c# - 为什么 double.IsNaN 有如此奇怪的实现

标签 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;
}

我的 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

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;
}

但不知道为什么

最佳答案

在 IEEE754 中,NaN 值被编码为具有 01 的符号位以及所有 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

给出 0x7ff00000000000009218868437227405312

关于c# - 为什么 double.IsNaN 有如此奇怪的实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19832493/

相关文章:

c# - 无法匹配 C# 中的时间

c# - 在C#中比较两个日期并计算差值

c# - HttpWebRequest,像 Fiddler 一样保持事件状态?

c# - PCSC智能卡读卡器 'friendly names'是如何构造的?

javascript - 1.265 * 10000 = 126499.99999999999?

c# - 十进制 ToString 格式,至少给出 1 位数字,没有上限

c# - 为什么我在调用 ContextRegistry.GetContext() 时收到 Spring.NET 引发的异常?

c# - 对象是如何存储在内存中的?

actionscript-3 - 如何让数字具有 0.05 的精度?

PHP 从数据库返回 float 而不是字符串?