floating-point - 对于IEEE754 NaN值,所有比较返回false的理由是什么?

标签 floating-point comparison nan ieee-754 iec10967

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

我想这以某种方式简化了数值计算,但是我找不到明确陈述的理由,甚至在Kahan的Lecture Notes on the Status of IEEE 754中也没有详细讨论其他设计决策。

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

编辑:
到目前为止,所有答案都表明,比较NaN毫无意义。

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

因此,在我看来,返回true或false进行比较的选择是任意的,
对于常规数据处理,如果遵循通常的法律将是有利的
(自反性==,三分法为<,==,>),
以免依赖这些定律的数据结构变得混乱。

因此,我要求打破这些法律的某些具体优势,而不仅仅是哲学推理。

编辑2:
我想我现在明白为什么将NaN设置为最大值是一个坏主意,它将使上限计算变得混乱。

NaN!= NaN可能需要避免检测诸如

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


然而,最好通过将绝对差与一个较小的限制进行比较来编写。
因此恕我直言,这是打破NaN自反性的相对较弱的论据。

最佳答案

我是IEEE-754委员会的成员,我将尽力帮助澄清一些事情。

首先,浮点数不是实数,并且浮点算术不满足实数算术的公理。三分法不是实数运算的唯一属性,它对浮点数不成立,甚至不是最重要的。例如:


加法不是关联的。
分配法不成立。
有没有反数的浮点数。


我可以继续。不可能指定一个固定大小的算术类型来满足我们所知道和喜欢的真实算术的所有属性。 754委员会必须决定弯曲或折断其中的一些。这遵循一些非常简单的原则:


如果可以,我们匹配实数运算的行为。
当我们无法做到时,我们会尝试使违规行为可预测且易于诊断。


关于您的评论“并不意味着正确答案是错误的”,这是错误的。谓词(y < x)询问y是否小于x。如果y为NaN,则它不小于任何浮点值x,因此答案必然为假。

我提到三分法不适用于浮点值。但是,确实存在类似的属性。 754-2008标准的第5.11条第2款:


  可能存在四个互斥关系:小于,相等,大于和无序。当至少一个操作数为NaN时,将出现最后一种情况。每个NaN都应将无序与所有事物(包括自身)进行比较。


就编写额外的代码来处理NaN而言,通常有可能(尽管并不总是那么容易)以适当的方式构造代码,以使NaN完全失效,但这并非总是如此。如果不是,则可能需要一些额外的代码,但这对于以代数闭包为浮点算术带来的便利来说是一个很小的代价。



附录:
许多评论者认为,采用NaN!= NaN似乎并没有保留任何熟悉的公理,因此保持平等和三分法的反身性会更有用。我承认对此观点有些同情,所以我想我将重新审视这个答案并提供更多背景信息。

通过与Kahan交谈,我的理解是NaN!= NaN源自两个务实的考虑:


x == y应尽可能与x - y == 0等效(除了作为实数算法的定理之外,这还使得比较的硬件实现更加节省空间,这在标准制定时就显得尤为重要。 (x = y = infinity)被违反,因此它本身并不是一个很大的理由;它可以合理地弯腰为(x - y == 0) or (x and y are both NaN)
更重要的是,在8087算法中将NaN形式化时没有isnan( )谓词;有必要为程序员提供一种方便有效的方法来检测NaN值,而这些值不依赖于编程语言,而提供isnan( )这样的代码可能要花费很多年。我将引用卡汉(Kahan)在该主题上的文章:



  如果没有摆脱NaN的方法,它们将像CRAY上的Infinites一样无用;一旦遇到一个问题,最好是停止计算,而不是无限期地继续计算以得出不确定的结论。这就是为什么对NaN进行的某些操作必须提供非NaN结果的原因。哪些操作? …例外是C个谓词“ x == x”和“ x!= x”,对于每个无穷或有限数x分别为1和0,但如果x不是数字(NaN),则相反。这些提供了NaN和数字之间唯一简单的,无例外的区分,即缺少NaN单词和谓词IsNaN(x)的语言中的数字。


注意,这也是排除返回“ Not-A-Boolean”之类的逻辑的逻辑。也许这种实用主义放错了地方,该标准应该要求isnan( ),但这将使NaN在全世界等待编程语言采用的几年中几乎无法高效,方便地使用。我不认为这是一个合理的权衡。

直言不讳:NaN == NaN的结果现在不会改变。学会与之相处比在网络上抱怨更好。如果您想主张还应该存在适合于容器的顺序关系,我建议提倡您喜欢的编程语言实现IEEE-754(2008)中标准化的totalOrder谓词。事实并非如此,这说明了卡汉(Kahan)的担忧之效,这激发了当前的局势。

关于floating-point - 对于IEEE754 NaN值,所有比较返回false的理由是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47413126/

相关文章:

python - 什么是 float ,我的想法正确吗?

python - 比较包含 NaN 的列表

python - 比较两个文件报告python中的差异

floating-point - 为什么偏置指数的值是 127 而不是 128?

c - 在 C 中翻转 double /浮点符号的最快方法

python - 随机将 float 舍入为整数

用于比较任何无符号和有符号整数的 C++ 模板函数

python - 在Python中用0替换NaN

python - Pandas groupby 和 rolling_apply 忽略 NaN

python - 不能在 Python 中删除空值