当你执行(-1 >>> 0)
您正在执行无符号右移。这里的未签名是关键。根据spec, 的结果>>>
始终未签名。-1
表示为二进制补码 of 1
。这就是二进制的全部1
s(在 8 位系统中,它是11111111
).
所以现在你通过执行使其未签名>>> 0
。你是说,“移动二进制表示-1
,这就是全部1
s,按零位(不做任何更改),但使其返回一个无符号数。”所以,你得到了所有的价值1
s。转到浏览器中的任何 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 1
s。例如,二的 3 次方(八)减一(七)是111
以二进制形式。
所以对于下一篇(-1 >>> 32) === (2**32 - 1)
....让我们看一些事情。我们知道二进制表示-1
is all 1
s。然后将其右移一位数,您将获得与所有值相同的值1
s 但前面加一个零(并返回一个无符号数)。
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
,这就是全部1
s 为二进制补码。我们将按照文档的最后一步将其移动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 0001
F 是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
是六位。所以我们取 321
s 并将其移零位!这就是为什么。答案依然是321
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!!!