javascript - Javascript 的 Shift right with zero-fill operator (>>>) 产生意想不到的结果
问题描述
首先,(-1 >>> 0) === (2**32 - 1)
我希望这是由于在左侧添加了一个新零,从而将数字转换为 33 位数字?
但是,为什么也是(-1 >>> 32) === (2**32 - 1)
如此,虽然我希望它(在将 32 位数移动 32 次并用零替换最高有效位之后)为 0。
不应该是平等的((-1 >>> 31) >>> 1) === 0
吗?还是我错过了什么?
解决方案
当您执行时,(-1 >>> 0)
您正在执行无符号右移。这里的未签名是关键。根据规范, 的结果>>>
始终是无符号的。-1
表示为两者的恭维。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**32 - 1
32 秒也是如此1
。例如,二的三次方(八)减一(七)是111
二进制的。
所以对于下一个(-1 >>> 32) === (2**32 - 1)
......让我们看一些事情。我们知道 的二进制表示-1
是 all 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 位。
那么你遇到了奇怪的情况,再移动一次应该为零,对吗?
根据规范:
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
是:
令 shiftCount 为屏蔽掉除 rnum 的最低有效 5 位之外的所有结果,即计算 rnum & 0x1F。
那么是什么rnum & 0x1F
?Well&
表示按位AND
运算。lnum
是左边的数字>>>
,rnum
是右边的数字。所以我们说32 AND 0x1F
。记住 32 是100000
. 0x
是十六进制的,其中每个字符都可以用4
位表示。1
是0001
和 F 是1111
。或(也以 10 为底0x1F
)也是如此。00011111
11111
31
2**5 - 1
console.log(0x1F) //31 (which is 11111)
32: 100000 &
0x1F: 011111
---------
000000
如果为零,则要移位的位数。这是因为前导不是最高有效位的一部分!是六位。1
32
5
32
所以我们取 321
秒并将其移零位!这就是为什么。答案仍然是 321
秒。
在示例中,-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!!!
推荐阅读
- varnish - 如果选项设置 beresp.do_gzip = true,则 varnishstat 中没有后端计数器 beresp_bodybytes;
- php - Symfony 5 - 获取角色层次结构以影响用户
- vue.js - 同步函数调用期间的Vue更新组件
- gremlin - 将 Ip 字符串转换为整数以检查它是否属于 CIDR 块
- flutter - 在颤振上创建一个菜单,用 Navigator.pop() 关闭
- vespa - Vespa.ai 中的内存文档存储
- reactjs - React JS 从另一个状态获取状态值
- javascript - 为什么 find 函数在比较 Vue 中的两个数据属性时不起作用?
- angular - SCRIPT1002:语法错误 - IE11 和 Angular
- java - 带有 MS SQL 的 MyBatis 未映射到 LocalDateTime