【问题标题】:Why does right shift on positive number sometimes result in a negative number?为什么正数右移有时会导致负数?
【发布时间】: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


【解决方案1】:

使用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

【讨论】:

  • 只回答了一半的问题。缺少“为什么”部分。
  • 感谢您的解释。我现在正在使用等价于右移的算术来解决这个问题。
【解决方案2】:

基本问题是 1562143596806 太大而无法容纳 32 位。它可以表示为Number,但是在执行按位运算时,该值首先转换为 32 位整数,这意味着“高位”在 移位之前已经被丢弃 - 的高位因此,结果不是从原始值填充的,它们是该临时 32 位值的符号的副本(或者使用 >>>,它们将为零,这并不是真正的改进)。结果恰好是负值只是一个意外,具体取决于输入的确切位模式,如果它是正值,它仍然是错误的正值。

如此大的值可以安全地处理为BigInt,但缺乏对此的支持。使用浮点运算可以工作,但需要格外小心。例如,您可以除以 256 并将结果取底,但您不能使用通常的 |0 来去除小数部分,因为即使除以 256 后,该值也太大而无法容纳 32 位。也存在各种非内置 BigInt 库来处理这类事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多