【问题标题】:double.NaN - how does this counterintuitive feature work?double.NaN - 这个违反直觉的功能是如何工作的?
【发布时间】:2011-05-30 16:57:04
【问题描述】:

我偶然发现了 .NET 在代码中对double.NaN 的定义:

public const double NaN = (double)0.0 / (double)0.0;

PositiveInfinityNegativeInfinity 的做法类似。

double.IsNaN(去掉一些#pragmas 和 cmets)定义为:

[Pure] 
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static bool IsNaN(double d) 
{
    if (d != d)
    { 
        return true; 
    }
    else 
    {
        return false;
    }
}

这对我来说非常违反直觉。

为什么将 NaN 定义为除以零? 0.0 / 0.0 如何代表“幕后”? double怎么能被0除,为什么NaN != NaN会这样?

【问题讨论】:

  • 这更多是关于 NaN 而不是 .NET 的细节......请参阅 en.wikipedia.org/wiki/NaN
  • double.NaN 的可能副本
  • @Jon Skeet:我同意,感谢您指出这一点并提供链接!稍微改变了问题,减少了 .NET 的特定性。
  • 它与 database-null 兼容。还有一条规则说 null != null

标签: double nan


【解决方案1】:

这里的答案很简单。 .Net 框架实现了 IEEE (System.Double complies with the IEC 60559:1989 (IEEE 754) standard for binary floating-point arithmetic.) 指定的浮点标准。这是因为浮点运算实际上必须在许多系统上工作,而不仅仅是 x86/64 架构,因此通过遵循约定可以确保更少的兼容性问题(例如将代码从 DSP 移植到 x86 处理器)。

至于 d != d,这是一个性能优化。基本上,这条指令依赖于一个硬件指令,它可以非常快速地确定两个双浮点数是否相等。根据标准,NAN != NAN 因此是最快的测试方式。正在为您寻找参考。

【讨论】:

  • 我不认为这是性能优化。相反,这是测试 NaN 的标准(并且可能是唯一可移植的)方法,根据定义起作用。
【解决方案2】:

为什么将 NaN 定义为除以 零?怎么能除以0 可能是双倍的,为什么 NaN != NaN?

所有这些都由IEEE 754 standard 强制执行,几乎所有现代 CPU 都实现了。

0.0 / 0.0 如何在“幕后”表示?

通过将所有位设置为 1 的指数和至少一位设置为 1 的尾数设置。请注意,这意味着有大量不同的位模式都表示 NaN - 但是,如上所述,即使位模式相同,它们也必须被视为不相等(即 == 必须返回 false)。

【讨论】:

    【解决方案3】:

    来自 C# 规范:

    14.9.2 浮点比较运算符 预定义的浮点比较运算符有:

    布尔运算符 ==(float x, float y);布尔运算符 ==(double x, double y);
    布尔运算符 !=(float x, float y);布尔运算符 !=(double x, double y);
    布尔运算符 布尔运算符 >(float x, float y);布尔运算符 >(double x, double y);
    布尔运算符 布尔运算符 >=(float x, float y);布尔运算符 >=(double x, double y);

    运算符根据 IEC 60559 标准的规则比较操作数: 如果任一操作数为 NaN,则除 != 以外的所有运算符的结果均为假,结果为真。 对于任何两个操作数,x != y 始终产生与 !(x = = y)。但是,当一个或两个操作数都是 NaN 时,、= 运算符不会产生与相反运算符的逻辑否定相同的结果。 [示例:如果 x 和 y 中的任何一个为 NaN,则 x = y) 为真。结束示例]

    关于 NaN 在幕后是如何表示的,IEEE 规范中的 wikipedia article 有一些例子。

    【讨论】:

      猜你喜欢
      • 2017-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      相关资源
      最近更新 更多