为什么NaN值的比较与所有其他值的比较行为不同? 也就是说,与运算符==,<=,>=,<,>的所有比较,其中一个或两个值都是NaN,返回false,与所有其他值的行为相反。

我认为这在某种程度上简化了数值计算,但我找不到一个明确的原因,甚至在Kahan的《IEEE 754状态讲义》中也找不到,他详细讨论了其他设计决策。

在进行简单的数据处理时,这种异常行为会造成麻烦。例如,当在C程序中对记录列表w.r.t.某个实值字段进行排序时,我需要编写额外的代码来处理NaN作为最大元素,否则排序算法可能会变得混乱。

编辑: 到目前为止,所有的答案都认为比较nan是没有意义的。

我同意,但这并不意味着正确答案是错误的, 而是一个非布尔型(NaB),幸运的是它并不存在。

所以在我看来,选择返回真或假进行比较是随意的, 对于一般的数据处理来说,如果它符合通常的规律,那将是有利的 (==的反身性,<,==,>的三分), 以免依赖这些定律的数据结构变得混乱。

所以我要求的是打破这些定律的一些具体好处,而不仅仅是哲学推理。

编辑2: 我想我现在明白为什么让NaN最大是一个坏主意了,它会搞砸上限的计算。

NaN != NaN可能是可取的,以避免检测循环中的收敛,例如

while (x != oldX) {
    oldX = x;
    x = better_approximation(x);
}

但是最好是通过比较小极限下的绝对差来写。 所以恕我直言,这是一个相对较弱的论点,打破自反性在NaN。


当前回答

NaN可以被认为是一个未定义的状态/数。类似于0/0未定义或根号(-3)的概念(在浮点数所在的实数系统中)。

NaN被用作这种未定义状态的一种占位符。从数学上讲,未定义并不等于未定义。你也不能说一个未定义值大于或小于另一个未定义值。因此,所有比较返回false。

这种行为在比较根号(-3)和根号(-2)的情况下也很有利。它们都会返回NaN,但它们并不等效,即使它们返回相同的值。因此,在处理NaN时,具有相等总是返回false是理想的行为。

其他回答

它看起来很奇怪,因为大多数允许nan的编程环境也不允许3值逻辑。如果你加入3值逻辑,它就会变得一致:

(2.7 == 2.7) = true (2.7 == 2.6) = false (2.7 == NaN) =未知 (NaN == NaN) =未知

甚至。net也不提供bool类型?operator==(double v1, double v2)运算符,所以你仍然被愚蠢的(NaN == NaN) = false结果所困扰。

从wikipedia关于NaN的文章来看,以下做法可能导致NaN:

All mathematical operations> with a NaN as at least one operand The divisions 0/0, ∞/∞, ∞/-∞, -∞/∞, and -∞/-∞ The multiplications 0×∞ and 0×-∞ The additions ∞ + (-∞), (-∞) + ∞ and equivalent subtractions. Applying a function to arguments outside its domain, including taking the square root of a negative number, taking the logarithm of a negative number, taking the tangent of an odd multiple of 90 degrees (or π/2 radians), or taking the inverse sine or cosine of a number which is less than -1 or greater than +1.

由于无法知道这些操作中的哪一个创建了NaN,因此无法对它们进行有意义的比较。

我不知道其设计原理,但以下是IEEE 754-1985标准的摘录:

应该能够比较所有支持格式的浮点数,即使操作数的格式不同。比较是精确的,不会溢出也不会溢出。可能存在四种互斥关系:小于、等于、大于和无序。当至少有一个操作数是NaN时,会出现最后一种情况。每个NaN都应该与一切事物,包括它自己,进行无序比较。”

因为数学是数字“仅仅存在”的领域。 在计算中,你必须初始化这些数字,并根据需要保持它们的状态。 在过去的日子里,内存初始化的工作方式是你永远无法依赖的。你永远不能允许自己这样想“哦,它会一直用0xCD初始化,我的算法不会坏”。

所以你需要合适的非混合溶剂,足够粘稠,不会让你的算法被卷入和破坏。 涉及数字的优秀算法大多使用关系,而那些if()关系将被省略。

这只是油脂,你可以在创建新变量,而不是从计算机内存编程随机地狱。不管你的算法是什么,都不会崩溃。

接下来,当您仍然突然发现您的算法正在生成nan时,可以将其清除,一次查看每个分支。同样,“总是错误”的规则在这方面很有帮助。

很简单的回答:

因为以下几点: Nan / Nan = 1 绝对不能持有。否则inf/inf等于1。

(因此nan不能等于nan。对于>或<,如果nan尊重满足阿基米德性质的集合中的任何顺序关系,我们将再次得到nan / nan = 1的极限)。