我是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 =无穷大,所以它本身并不是一个很大的理由;它可能已经被合理地弯腰到(x - y == 0) or (x and y are both NaN)
)。
更重要的isnan( )
是,在8087算术中没有正式使用NaN的谓词。有必要为程序员提供一种便捷有效的方法来检测NaN值,而这些值不依赖于编程语言,而NaN值isnan( )
可能需要花费很多年。我将引用卡汉(Kahan)在该主题上的著作:
没有办法摆脱NaN,它们将像CRAY上的Indefinites一样无用;一旦遇到一个问题,最好是停止计算,而不是无限期地继续计算以得出不确定的结论。这就是为什么对NaN进行的某些操作必须提供非NaN结果的原因。哪些操作?…例外是C谓词“ x == x”和“ x!= x”,对于每个无穷或有限数x分别为1和0,但如果x不是数字(NaN),则相反。这些提供了NaN和数字之间唯一简单的,无例外的区分,即缺少NaN单词和谓词IsNaN(x)的语言中的数字。
请注意,这也是排除返回“ Not-A-Boolean”之类的逻辑的逻辑。也许这种实用主义是放错了地方,而该标准应该是必需的isnan( )
,但这将使NaN在全世界等待编程语言采用的几年中几乎无法高效,方便地使用。我不认为这是一个合理的权衡。
直言不讳:NaN == NaN的结果现在不会改变。学会与之相处比与在网络上抱怨更好。如果您想主张还应该存在适合于容器的顺序关系,我建议提倡您最喜欢的编程语言实现totalOrder
IEEE-754(2008)中标准化的谓词。事实尚未证明Kahan引起当前状况的担忧的有效性。
while (fabs(x - oldX) > threshold)
如果发生收敛或NaN进入计算,则循环结构通常会变成,退出循环。然后,NaN的检测和适当的补救措施将在循环之外发生。