Javascript 的 Shift right with zero-fill operator (>>>) 产生意想不到的结果

标签 javascript bit-manipulation

一、(-1 >>> 0) === (2**32 - 1)我期望这是由于在左侧添加了一个新零,从而将数字转换为 33 位数字?
但是,为什么是 (-1 >>> 32) === (2**32 - 1)同样,虽然我希望它(在将 32 位数移动 32 次并用零替换最高有效位之后)为 0。
不应该等于((-1 >>> 31) >>> 1) === 0 ?还是我错过了什么?

最佳答案

当你执行 (-1 >>> 0)您正在执行无符号右移。这里的未签名是关键。根据 spec>>> 的结果总是无符号的。 -1表示为 two's compliment1 .这在二进制中都是 1 s (在 8 位系统中为 11111111 )。
因此,现在您通过执行 >>> 0 使其未签名.你是说,“将 -1 的二进制表示,即所有 1 s 移动零位(不做任何更改),但让它返回一个无符号数。”因此,您将获得所有 1 的值。转到浏览器中的任何 javascript 控制台并键入:

console.log(2**32 - 1) //4294967295
// 0b means binary representation, and it can have a negative sign
console.log(0b11111111111111111111111111111111) //4294967295
console.log(-0b1 >>> 0) //4294967295
记住 2 **任何减去 1 的数字总是二进制的。它的数量与您将两个提升到的功率相同。所以2**32 - 1是 32 1 s。例如,二的三次方(八)减去一(七)是111二进制。
所以对于下一个(-1 >>> 32) === (2**32 - 1) ....让我们看一些事情。我们知道 -1 的二进制表示都是1 s。然后将其右移一位,您将获得与所有 1 相同的值s 但在它前面加一个零(并返回一个无符号数)。
console.log(-1 >>> 1) //2147483647
console.log(0b01111111111111111111111111111111) //2147483647
继续移动,直到你有 31 个零和一个 1在最后。
console.log(-1 >>> 31) //1
这对我来说很有意义,我们有 31 0 s 和单个 1现在是我们的 32 位。
那么你遇到了奇怪的情况,再移动一次应该为零,对吗?
根据 spec :
6.1.6.1.11 Number::unsignedRightShift ( x, y )
Let lnum be ! ToInt32(x).
Let rnum be ! ToUint32(y).
Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.
Return the result of performing a zero-filling right shift of lnum by shiftCount bits. Vacated bits are filled with zero. The result is an unsigned 32-bit integer.
所以我们知道我们已经有 -1 ,这是全部1两口子恭维。我们将按照文档的最后一步将其移动 shiftCount位(我们认为是 32)。和shiftCount是:

Let shiftCount be the result of masking out all but the least significant 5 bits of rnum, that is, compute rnum & 0x1F.


那么rnum & 0x1F是什么? ?嗯&表示按位 AND手术。 lnum>>> 的左数和 rnum是它的右数。所以我们说32 AND 0x1F .记住 32 是 100000 . 0x是十六进制,其中每个字符可以用 4 表示位。 10001 F 是 1111 .所以0x1F0001111111111 (31 以 10 为底,2**5 - 1 也是)。
console.log(0x1F) //31 (which is 11111)

  32: 100000 &
0x1F: 011111
     ---------
      000000
如果为零,则要移位的位数。 这是因为前导 132不属于 5最重要的位! 32是六位。 所以我们取 32 1 s 并将其移零位!这就是为什么。答案仍然是 32 1 s。
关于示例 -1 >>> 31这是有道理的,因为 31 是 <= 5位。所以我们做了
  31: 11111 &
0x1F: 11111
      -------
      11111
并转移它31位....正如预期的那样。
让我们进一步测试一下......让我们做
console.log(-1 >>> 33) //2147483647
console.log(-1 >>> 1)  //2147483647
这是有道理的,只需将其移动一点。
  33: 100001 &
0x1F: 011111
      ---------
      00001
所以,过去 5位运算符的位并感到困惑。想和一个没有研究过 ECMAScript 来回答 stackoverflow 帖子的人玩木偶吗?只是问为什么这些是一样的。
console.log(-1 >>> 24033) //2147483647
console.log(-1 >>> 1)     //2147483647
那当然是因为
console.log(0b101110111100001) // 24033 
console.log(0b000000000000001) // 1
//                      ^^^^^ I only care about these bits!!!    

关于Javascript 的 Shift right with zero-fill operator (>>>) 产生意想不到的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63276182/

相关文章:

c - DES - 位和逆排列

c# - 将多个值编码为单个 long

Java 表达式等价

javascript - 滚动经过元素时更改 div/span 颜色?

c++ - 这段获取最低位位置的代码是如何工作的?

mysql - h2 数据库按位操作(&)语法无效 MySql

javascript - 将jquery中的逗号分隔列表转换为无序列表

c# - 在 ASP.Net 中使用 Javascript 显示隐藏文本框

javascript - Angular 三元运算符?具有功能

javascript - 向下滚动时淡化文本+图标。再次出现在顶部