我想找到小于数组中某个值的值。 我尝试使用Number.EPSILON,因为输入值不是一个确定值(例如1.5000000000001)。
我在测试过程中发现了一些奇怪的东西:
>> (1.5 < 1.5 + Number.EPSILON)
<- true
>> (2.5 < 2.5 + Number.EPSILON)
<- false
这是为什么? 测试环境是Chrome浏览器控制台。
答案 0 :(得分:6)
尽管Number.EPSILON
本身可以精确表示,但这并不保证向其添加值(或进一步对其进行任何操作)将获得完美的精度。在这种情况下,1.5 + Number.EPSILON
得出的数字略高于1.5:
console.log(1.5 + Number.EPSILON);
显然大于1.5。另一方面,在Number.EPSILON
上加上2.5的结果恰好是2.5-您希望得到的精度在加法过程中丢失了。
console.log(2.5 + Number.EPSILON);
2.5 < 2.5
评估为false
,符合预期。
答案 1 :(得分:1)
浮点数的精度有限。根据语言和体系结构的不同,它们通常使用32位(float
)或64位(double
,以“双精度”为代表)表示。尽管在诸如JavaScript之类的非类型化语言中事情变得模糊起来,但是在这一切之下仍然存在一台实际的计算机,并且该计算机必须执行浮点运算。
问题在于,由于精度有限,某些计算的结果无法准确表示。 Wikipedia page about floating point artithmetic上的一些示例对此进行了说明。
对于需要所有细节的人们,通常推荐有关What Every Computer Scientist Should Know About Floating-Point Arithmetic的文章。但要认真地:并不是每个计算机科学家都需要了解所有这一切,而且我敢肯定,世界上只有少数人真正阅读了整件事。... >
作为一个过度暗示的示例:假设您有5位数字来存储数字。然后当您添加
10000.
+ 0.00001
--------------------
= 10000.
.00001
部分将基本上被“截断”,因为它不适合5位数字。
(这并非完全如此,但是应该可以理解)
根据the documentation,Number.EPSILON
的实际值大约为 2.22 * 10-16 ,并且是“ 1与最小浮点数之间的差点数大于1“ 。 (有时称为ULP, Unit In The Last Place)。
因此将此值添加到1.0将产生不同的数字。但是将其添加到2.5将不会产生一个不同的数字,因为2.5与最小浮点数大于2.5的差比该epsilon大。这样,ε被截断了,就像上面的示例中的.00001
。
某些语言/库可能提供“ ulp”功能,该功能返回给定值和下一个较大的可表示值之间的差。例如,在Java中,您有
System.out.println(Math.ulp(1.0)); // Prints 2.220446049250313E-16
System.out.println(Math.ulp(2.5)); // Prints 4.440892098500626E-16
第一个显然是存储在Number.EPSILON
中的内容。第二个是加到2.5时应产生不同值的值。所以
2.5 < 2.5 + 4.4408E-16
将是false
和2.5 < 2.5 + 4.4409E-16
将是true
答案 2 :(得分:0)
Number.EPSILON是:
1与最小浮点数之间的差较大 比1
让我们说这个数字是0.00000000000000000000000001。
现在
1.5 < 1.5 + 0.00000000000000000000000001 === true
,当您要添加的极小部分的基数变大时,JS数学评估的精度计算将找到其边界。
2 < 2 + 0.00000000000000000000000001 === false