max*_*max 114 language-agnostic floating-point nan ieee-754
相关的IEEE标准定义了一个数字常量NaN(不是数字),并规定NaN应该比较为不等于它自己.这是为什么?
我熟悉的所有语言都实现了这个规则.但它经常会导致严重的问题,例如当NaN存储在容器中时,NaN存在于正在排序的数据中等时的意外行为等.更不用说,绝大多数程序员都希望任何对象都等于自身(在他们了解NaN之前,令人惊讶的是他们增加了错误和混乱.
IEEE标准经过深思熟虑,因此我确信NaN的比较与其本身相同是很糟糕的.我只是想不通它是什么.
rus*_*hop 145
接受的答案是100%毫无疑问错误.不是错误的一半,甚至是错误的错误.我担心这个问题会在搜索中弹出这个问题的时候长时间混淆和误导程序员.
NaN被设计为通过所有计算传播,像病毒一样感染它们,所以如果你在深度,复杂的计算中的某个地方遇到NaN,你就不会冒出一个看似明智的答案.否则通过身份NaN/NaN应该等于1,以及所有其他后果,如(NaN/NaN)== 1,(NaN*1)== NaN等.如果你想象你的计算在某处出错了(舍入产生了一个零分母,产生NaN)等,那么你可能会因为你的计算而得到非常不正确(或者更糟:微妙的错误)的结果而没有关于原因的明显指标.
在探究数学函数的值时,NaNs在计算中也有很好的理由; 链接文档中给出的一个示例是找到函数f()的零().完全可能的是,在使用猜测值探测函数的过程中,您将探测函数f()不会产生明显结果的函数.这允许zeros()查看NaN并继续其工作.
NaN的替代方案是在遇到非法操作(也称为信号或陷阱)时立即触发异常.除了您可能遇到的巨大性能损失之外,当时无法保证CPU会在硬件中支持它,或者OS /语言会在软件中支持它; 在处理浮点时,每个人都有自己独特的雪花.IEEE决定在软件中明确地将其作为NaN值处理,因此它可以在任何操作系统或编程语言中移植.正确的浮点算法通常在所有浮点实现中都是正确的,无论是node.js还是COBOL(hah).
理论上,您不必设置特定的#pragma指令,设置疯狂的编译器标志,捕获正确的异常,或安装特殊的信号处理程序,以使看似相同的算法实际上正常工作.不幸的是,一些语言设计师和编译器编写者已经非常忙于尽最大努力撤消此功能.
请阅读有关IEEE 754浮点历史的一些信息.对于委员会成员回答的类似问题,这个答案也是如此:对于IEEE754 NaN值,所有比较返回错误的理由是什么?
Nie*_*sol 101
好吧,log(-1)
给予NaN
,acos(2)
也给出NaN
.这是否意味着log(-1) == acos(2)
?显然不是.因此,它完全合理,NaN
不等于自身.
两年后重新审视这一点,这是一个"NaN安全"比较功能:
function compare(a,b) {
return a == b || (isNaN(a) && isNaN(b));
}
Run Code Online (Sandbox Code Playgroud)
max*_*max 31
我的原始答案(从4年前开始)批评现代观点的决定,而不理解作出决定的背景.因此,它没有回答这个问题.
NaN
!=NaN
起源于两个实用的考虑因素:[...]当时没有
isnan( )
断言NaN在8087算术中被形式化; 有必要为程序员提供一种方便有效的方法来检测不依赖于编程语言的NaN值,从而提供isnan( )
可能需要很多年的时间
这种方法有一个缺点:它使NaN在许多与数值计算无关的情况下变得不那么有用.例如,很久以后当人们想要用来NaN
表示缺失值并将它们放在基于散列的容器中时,他们就无法做到.
如果委员会预见到未来的使用案例,并认为它们足够重要,那么它们可能会更加冗长!(x<x & x>x)
而不是x!=x
作为测试NaN
.然而,他们的重点更加务实和狭隘:为数值计算提供最佳解决方案,因此他们认为他们的方法没有问题.
===
原始答案:
对不起,我很欣赏进入最高投票回答的想法,我不同意.NaN并不意味着"未定义" - 请参阅http://www.cs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF,第7页(搜索"undefined"一词).正如该文件所证实的那样,NaN是一个定义明确的概念.
此外,IEEE方法是尽可能遵循常规数学规则,当它们不能时,遵循"最少惊喜"的规则 - 请参阅/sf/answers/110160081/.任何数学对象都等于它自己,所以数学规则意味着NaN == NaN应该是真的.我看不出任何有效和有力的理由偏离这样一个重要的数学原理(更不用说比较三分法的不太重要的规则等).
结果,我的结论如下.
IEEE委员会成员并没有非常清楚地认为这一点,并犯了一个错误.由于很少有人理解IEEE委员会的做法,或者关心NaN的标准究竟是什么(也就是说:大多数编译器对NaN的处理都违反了IEEE标准),没有人发出警报.因此,这个错误现在已经嵌入到标准中.它不太可能被修复,因为这样的修复会破坏很多现有的代码.
编辑:这是一篇非常翔实的讨论中的一篇文章.注意:要获得无偏见的视图,您必须阅读整个线程,因为Guido对其他一些核心开发人员的看法不同.然而,Guido对这个话题并不感兴趣,并且很大程度上遵循了Tim Peters的建议.如果有人赞成Tim Peters的观点NaN != NaN
,请在评论中添加; 他们很有可能改变我的观点.
一个不错的属性是:if x == x
返回false,然后x
是NaN.
(可以使用这个属性来检查,如果x
是NaN
或不是.)
试试这个:
var a = 'asdf';
var b = null;
var intA = parseInt(a);
var intB = parseInt(b);
console.log(intA); //logs NaN
console.log(intB); //logs NaN
console.log(intA==intB);// logs false
Run Code Online (Sandbox Code Playgroud)
如果intA == intB为真,那可能会导致你得出a == b,但显然不是.
另一种看待它的方法是,NaN只是为您提供有关什么不是什么,而不是它是什么的信息.例如,如果我说'苹果不是大猩猩'和'橙子不是大猩猩',你会得出结论'苹果'=''橙色'吗?
归档时间: |
|
查看次数: |
34138 次 |
最近记录: |