【发布时间】:2019-11-13 22:07:49
【问题描述】:
在 javascript 中右移数字有时会产生负数。这背后的原因是什么?可以缓解吗?
const now = 1562143596806 // UNIX timestamp in milliseconds
console.log(now >> 8) // -4783199
【问题讨论】:
标签: javascript binary bit-manipulation bitwise-operators
在 javascript 中右移数字有时会产生负数。这背后的原因是什么?可以缓解吗?
const now = 1562143596806 // UNIX timestamp in milliseconds
console.log(now >> 8) // -4783199
【问题讨论】:
标签: javascript binary bit-manipulation bitwise-operators
使用zero-fill right shift 运算符 (>>>) 始终获得肯定的结果:
const now = 1562143596806 // UNIX timestamp in milliseconds
console.log(now >>> 8)
>> 运算符返回数字的原因是,最初,数字在内部表示为 64-bit floating point number:
10110101110110111000000111010000100000110
移位操作首先将操作数转换为 32 位整数。它通过仅保留 32 个最低有效位并丢弃其余位来做到这一点:
10110111000000111010000100000110
然后它会在保持符号不变的情况下将它移动指定的位数,即从左边移入 8 个1 位:
11111111101101110000001110100001
转换回十进制,得到:
-4783199
【讨论】:
基本问题是 1562143596806 太大而无法容纳 32 位。它可以表示为Number,但是在执行按位运算时,该值首先转换为 32 位整数,这意味着“高位”在 在移位之前已经被丢弃 - 的高位因此,结果不是从原始值填充的,它们是该临时 32 位值的符号的副本(或者使用 >>>,它们将为零,这并不是真正的改进)。结果恰好是负值只是一个意外,具体取决于输入的确切位模式,如果它是正值,它仍然是错误的正值。
如此大的值可以安全地处理为BigInt,但缺乏对此的支持。使用浮点运算可以工作,但需要格外小心。例如,您可以除以 256 并将结果取底,但您不能使用通常的 |0 来去除小数部分,因为即使除以 256 后,该值也太大而无法容纳 32 位。也存在各种非内置 BigInt 库来处理这类事情。
【讨论】: