为什么在 JavaScript 中用 0 进行位移在某些情况下会产生奇怪的结果

Why bitwise shift with 0 in JavaScript yields weird results in some cases

刚刚在 JavaScript 中尝试了不寻常的按位运算,在某些情况下我得到了一些奇怪的结果:

一般情况

1 << 0            // returns 1, makes sense
100 << 0          // returns 100, makes sense
100 >> 0          // returns 100, definitely makes sense

但是这些,当移动0位时,全部产生零

9E99 << 0         // returns 0 ..... Why all bits are cleared?
9E99 >> 0         // returns 0 also  ..... All bits cleared?
Infinity >> 0     // returns 0
Infinity << 0     // returns 0
-Infinity << 0    // returns 0 .... Can't explain why
-0 << 0           // also yields 0 not -0 itself
-0 >> 0           // also resolved to 0

无穷大和位移位怎么办

1 << Infinity     // returns 1  .. no changes
1024 << Infinity  // returns 1024 .. no changes
1024 >> Infinity  // returns 1024 .. no changes either
Infinity >> Infinity      // 0
Infinity << Infinity      // 0

上面那些案例对我来说意义不大。 将整数移动零位时,值不变但是当你将Infinity移动0位时,它实际上returns你0。为什么?

我认为将任何数值移动 0 位不应该改变它的值,不是吗?

此外,当将一个小整数值移动无限位时,该值根本不会改变。但是当您将 Infinity 移动任何值时,它会被 0 代替。

我很好奇为什么会出现这些现象?是否有任何规范或理论可以解释这些奇怪的行为?

JavaScript 中的移位和逻辑运算被评估为 32 位整数。 << 运算符的存在要求将任何对象转换为 int 或如果转换失败则为 0。 Infinity 或 99e9 是有效的 ieee double,但无法转换为 int:9e99 mod 2^32 == 0。一个反例 9e9|0 == 41006540​​8 说明了 mod 元代数的用法。

这是双向的:inf << inf 等同于 0 << 0。

来自 MDN:

The operands of all bitwise operators are converted to signed 32-bit integers in two's complement format.

JavaScript中的所有数字都是IEEE754 double precision floating point numbers。在应用按位运算符之前,它们被转换为 32 位整数。

更准确地说,这个过程在ToInt32 in the spec:

中有描述

如你所见,Infinities 和 -0 的变换被精确地描述了。

这是一个二进制截断,这也解释了为什么9E99变成了0:如果你看(9E99).toString(2)右边的32位,这个最明显(将其粘贴到您的控制台中,它们都是 0).

根据ECMA-262.

基本上,JS 编译器使用 ECMA-262 第 9.5 项中描述的算法将浮点参数转换为 32 位整数。在大多数情况下,您提到的转换结果是 0。