4

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

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

这在PositiveInfinity和中类似地完成NegativeInfinity

double.IsNaN(删除一些#pragmas 和注释)定义为:

[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“幕后”如何表现?怎么可能除以0 double,为什么NaN != NaN

4

3 回答 3

6

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

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

于 2010-12-25T19:47:02.930 回答
2

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

所有这些都是IEEE 754 标准规定的,几乎所有现代 CPU 都实施了该标准。

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

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

于 2010-12-25T20:14:47.977 回答
0

来自 C# 规范:

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

布尔运算符 ==(float x, float y); 布尔运算符 ==(双 x, 双 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);
布尔运算符 <=(float x, float y); bool 运算符 <=(double x, double y);
布尔运算符 >=(float x, float y); 布尔运算符 >=(双 x, 双 y);

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

至于如何在幕后表示 NaN,有关 IEEE 规范 的维基百科文章有一些示例。

于 2010-12-25T19:54:41.283 回答