为什么在 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 == 410065408 说明了 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。
刚刚在 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 == 410065408 说明了 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。