为什么Number.EPSILON在不同的操作数上作用不同?

时间:2019-07-25 18:29:23

标签: javascript floating-point

考虑条件

(-1 - Number.EPSILON < -1) === (-2 - Number.EPSILON < -2)

此示例在我的计算机上的Chrome控制台中执行false(?!),但我不知道为什么(左侧为true,右侧为false)。在Edge和Firefox中,整个条件也执行到false,在Internet Explorer(??!?)中但执行true

What happens on Chrome console

2 个答案:

答案 0 :(得分:3)

浮点数以零为中心。也就是说,它们在0附近最密集;数字越大,数字线在该区域中存在的浮点数越少。

不良ASCII近似值:

---------------------------------------(-1)-----(0)-----(1)------------------------------------------
 .        .     .    .    .  .  .  . . . .................. . . .  .  .  .    .    .    .        .

上一行代表实数;下面的点标记可能的浮点值。 -1和1之间有许多可能的浮点值,从而可以实现非常精细的区分。离0越远,可能的浮点值就越稀疏,这意味着以较低的精度存储较大的数字。

Number.EPSILON是1与下一个较高的浮点数之间的距离。这意味着1 + Number.EPSILON作为浮点值存在并且可以准确表示。同样适用于-1 - Number.EPSILON,该值相同,但带有负号。

但是,2 + Number.EPSILON不存在。因为1比2更接近0,所以浮点数在1周围比2周围更密集。特别是2与下一个较高的浮点值之间的差大于Number.EPSILON(实际上,如果结果是2 * Number.EPSILON,我不会感到惊讶。由于2 + Number.EPSILON无法精确表示,因此将其舍入为最接近的浮点数,该数本身就是2:

console.log(2 + Number.EPSILON === 2);  // true

对于Internet Explorer:does not support Number.EPSILON,所以

-1 - Number.EPSILON < -1

被评估为

-1 - undefined < -1

Number.NaN < -1,其值(与涉及NaN的所有比较一样)的计算结果为false

答案 1 :(得分:1)

JavaScript数字是双精度浮点数字(64位)。其中0-51位代表小数,其余位代表指数。

如果您尝试将Number.EPSILON转换为二进制文件-您会发现它是:

>  Number.EPSILON.toString(2)
'0.0000000000000000000000000000000000000000000000000001'

第一位是0,因此,如果加1-它变为1,它仍然适合小数位:

>  (1 + Number.EPSILON).toString(2)
'1.0000000000000000000000000000000000000000000000000001'
//---- So -----
(1+Number.EPSILON) !== 1

但是,当您添加2(二进制10)时,它会捕获到左侧的其他位-因此,右边的(不太重要的)位被切掉了,以适合小数位。

2 + Number.EPSILON
10.000000000000000000000000000000000000000000000000000|1  <- right bit dropped
                                                      ^
                                                      51 bit
//---- So -----
(2+Number.EPSILON) === 2