在javascript中右移数字有时会导致负数。背后的原因是什么?可以缓解吗?
const now = 1562143596806 // UNIX timestamp in milliseconds
console.log(now >> 8) // -4783199
答案 0 :(得分:3)
使用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
答案 1 :(得分:1)
基本问题是1562143596806太大而无法容纳32位。它可以表示为Number
,但是在执行按位运算时,该值首先转换为32位整数,这意味着在移位之前 的“高位”已经被删除-高位因此,结果的位不会从原始值中填充,它们是该临时32位值的符号的副本(或者对于>>>
,它们将为零,这并不是真正的改进)。根据输入的确切位模式,结果恰好是负数只是偶然,如果它是正数,那么它仍将是错误的正值。
可以安全地将如此大的值作为BigInt
进行操作,但是缺少对此的支持。使用浮点算法可以工作,但需要格外小心。例如,您可以除以256并将结果取底,但是您不能使用常规的|0
来去除小数部分,因为即使被256除后,该值仍然太大而无法容纳32位。也存在各种非内置的BigInt库来处理这种事情。