Javascript 的右移与零填充运算符 (>>>) 产生意外的结果

2023-11-26

First, (-1 >>> 0) === (2**32 - 1)我期望这是由于在左侧添加了一个新的零,从而将数字转换为 33 位数字?

但是,为什么是(-1 >>> 32) === (2**32 - 1)同样,虽然我期望它(在将 32 位数字移位 32 次并用零替换最高有效位之后)为 0。

不应该是平等的吗((-1 >>> 31) >>> 1) === 0?或者我错过了什么吗?


当你执行(-1 >>> 0)您正在执行无符号右移。这里的未签名是关键。根据spec, 的结果>>>始终未签名。-1表示为二进制补码 of 1。这就是二进制的全部1s(在 8 位系统中,它是11111111).

所以现在你通过执行使其未签名>>> 0。你是说,“移动二进制表示-1,这就是全部1s,按零位(不做任何更改),但使其返回一个无符号数。”所以,你得到了所有的价值1s。转到浏览器中的任何 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 的幂的数量相同。所以2**32 - 1 is 32 1s。例如,二的 3 次方(八)减一(七)是111以二进制形式。

所以对于下一篇(-1 >>> 32) === (2**32 - 1)....让我们看一些事情。我们知道二进制表示-1 is all 1s。然后将其右移一位数,您将获得与所有值相同的值1s 但前面加一个零(并返回一个无符号数)。

console.log(-1 >>> 1) //2147483647
console.log(0b01111111111111111111111111111111) //2147483647

继续移位,直到有 31 个零和一个1在最后。

console.log(-1 >>> 31) //1

这对我来说很有意义,我们有 310和一个单一的1现在是我们的 32 位。

那么你遇到了奇怪的情况,再移动一次应该为零,对吗?

Per the 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,这就是全部1s 为二进制补码。我们将按照文档的最后一步将其移动shiftCount位(我们认为是 32)。和shiftCount is:

令shiftCount 为屏蔽掉rnum 中除最低有效5 位之外的所有结果,即计算rnum & 0x1F。

那么什么是rnum & 0x1F? Well &表示按位AND手术。lnum是左边的数字>>> and rnum是它右边的数字。所以我们说32 AND 0x1F。请记住 32 是100000. 0x是十六进制,其中每个字符可以表示为4 bits. 1 is 0001F 是1111. So 0x1F is 00011111 or 11111 (31以 10 为基数,2**5 - 1 also).

console.log(0x1F) //31 (which is 11111)

  32: 100000 &
0x1F: 011111
     ---------
      000000

如果为零,则要移位的位数。这是因为领先的1 in 32不属于5最重要的位!32是六位。所以我们取 321s 并将其移零位!这就是为什么。答案依然是321s.

就例子而言-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!!!    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Javascript 的右移与零填充运算符 (>>>) 产生意外的结果 的相关文章

随机推荐