double.NaN - 这个违反直觉的功能是如何工作的?

Posted

技术标签:

【中文标题】double.NaN - 这个违反直觉的功能是如何工作的?【英文标题】:double.NaN - how does this counterintuitive feature work? 【发布时间】: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 【参考方案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 有一些例子。

【讨论】:

以上是关于double.NaN - 这个违反直觉的功能是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

Javascript (ECMAScript5) 的细节和违反直觉的地方

Javascript (ECMAScript5) 的细节和违反直觉的地方

为啥 Double.NaN==Double.NaN 返回 false?

如何在 C# 中处理接受 IComparable 的通用方法的 double.NaN

在我的自定义函数中返回 double.NaN:这是一个好习惯吗?

为啥 float.NaN != double.NaN 在 C# 中?