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

Javascript 为什么Number.EPSILON在不同的操作数上作用不同?,javascript,floating-point,Javascript,Floating Point,考虑条件 (-1 - Number.EPSILON < -1) === (-2 - Number.EPSILON < -2) (-1-Number.EPSILON

考虑条件

(-1 - Number.EPSILON < -1) === (-2 - Number.EPSILON < -2)
(-1-Number.EPSILON<-1)==(-2-Number.EPSILON<-2)
这个例子在我的机器上的Chrome控制台中执行到
false
(?!),但我不知道为什么(左边部分为true,右边部分为false)。在Edge和Firefox中,整个条件也执行到
false
,但在Internet Explorer中执行到
true
(??)


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
2+Number.EPSILON

10.000000000000000000000000000000000000000000000 | 1JavaScript数字是双精度浮点数(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
2+Number.EPSILON

10.000000000000000000000000000000000000000000000000 | 1浮点数以零为中心。也就是说,它们在0左右最密集;数字的大小越大,该数字行区域中的浮点数就越少

错误的ASCII近似值:

-------------------------------------(-1)---(0)---(1)------------------------------------------
.        .     .    .    .  .  .  . . . .................. . . .  .  .  .    .    .    .        .
上面一行代表实数;下面的点标记可能的浮点值。在-1和1之间有许多可能的浮点值,允许进行非常细粒度的区分。离0越远,可能的浮点值越稀疏,这意味着存储的数字越大,精度越低

是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
浮点数以零为中心。也就是说,它们在0左右最密集;数字的大小越大,该数字行区域中的浮点数就越少

错误的ASCII近似值:

-------------------------------------(-1)---(0)---(1)------------------------------------------
.        .     .    .    .  .  .  . . . .................. . . .  .  .  .    .    .    .        .
上面一行代表实数;下面的点标记可能的浮点值。在-1和1之间有许多可能的浮点值,允许进行非常细粒度的区分。离0越远,可能的浮点值越稀疏,这意味着存储的数字越大,精度越低

是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
是因为
2+Number.EPSILON===2
,这是因为浮点数的性质。可能是浮点数。如果您在
MDN
检查,就会发现
Number.EPSILON
是。因此,很可能在internet explorer上,
Number.EPSILON
被计算为
undefined
@melpomene,谢谢,但是为什么
1+Number.EPSILON!==1
?你明白梅尔波默尼的答案吗?如果没有,以下内容是否有帮助?考虑一个三位的十进制浮点格式。它可以表示1.23、3.79、32.1966、.722等等,但不能表示1.234,因为它有四个数字。对于这种格式,
Number.EPSILON
is.01这是从1.00到1.01的最小步长。但从10.0开始,下一步是10.1。我们不能去10点01分<代码>数字。ε
按1缩放。在二进制浮点中,2类似于10;它比1多了一个二进制数字。