为什么在JavaScript中“(2.5 <2.5 + Number.EPSILON)”是错误的?

时间:2019-06-04 04:46:06

标签: javascript precision epsilon

我想找到小于数组中某个值的值。 我尝试使用Number.EPSILON,因为输入值不是一个确定值(例如1.5000000000001)。

我在测试过程中发现了一些奇怪的东西:

>> (1.5 < 1.5 + Number.EPSILON) 
<- true 
>> (2.5 < 2.5 + Number.EPSILON)
<- false

这是为什么? 测试环境是Chrome浏览器控制台。

3 个答案:

答案 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 documentationNumber.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