繁体   English   中英

我需要对 ((2^32-1) << 0) 在 Javascript 中导致 -1 的解释(和可能的解决方法)

[英]I need an explanation (and possible workaround) for ((2^32-1) << 0) resulting -1 in Javascript

编辑:最后解释。

我试图使用 Uint32Array 实现一个 64 位整数类,并在两个 uint32 成员上执行按位运算。 我很快发现,就我对规范的理解而言,按位运算返回一个有符号的 32 位整数。 最初我希望 Uint32Array 会处理符号位,但事实并非如此。

我尝试围绕符号问题进行编码,但我被困在我根本无法理解的事情上

var a = (Math.pow(2, 32)-1); //set a to uint32 max value

到现在为止还挺好。

a.toString(2);// gives "11111111111111111111111111111111", as expected

然而:

(a << 0);             // gives "-1"
(a >> 1);             // gives "-1"
(a << 0) == (a >> 1); // evaluates to true

即使 JS 按位运算将数字转换为有符号的 32 位整数,向右移动 1 的 32 个设置位也不应该是 -1。 或者他们应该? 移位 0 位的非零数是否应等于其自身移位 1 位? 这是一个错误吗? 我遇到了未定义的行为吗?

通常类似问题的答案与带符号的 32 位转换有关,但我看不出这应该如何导致这种行为。

EDIT2,解释:我困惑的原因是对负数如何用二进制表示的根本误解。 虽然第一位实际上是符号位,1 表示负数,0 表示正数,但其余位并不像我假设的那样仅用于存储 abs()。

有符号 4 位示例: 0111等于+7 1111等于-7 ,它等于-1 我们如何以消极的方式结束? 因为1111的二进制补码0001 要获得数字的二进制补码,请翻转所有位并加一: 1111 -> 0000 -> 0001

现在我知道了,理解11..11 << 0-1很容易。 它与我的 4bit 示例完全相似。 11..11 >> 1-1现在也完全11..11 >> 1预期。 带符号的右移>>是 1 填充,因此11..11 >> 1仍然是11..11 ,它仍然是-1

我暂时保留这个,因为我当然不是唯一一个误解二进制有符号整数表示的人。 谢谢大家的时间。

即使 JS 按位运算将数字转换为有符号的 32 位整数,向右移动 1 的 32 个设置位也不应该是 -1。 或者他们应该? 移位 0 位的非零数是否应等于其自身移位 1 位? 这是一个错误吗? 我遇到了未定义的行为吗?

这是正常的、预期的和定义的。 是的,他们应该。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Right_shift是你使用的,它的描述是这样的:

右移运算符 (>>) 将第一个操作数右移指定的位数。 右移的多余位被丢弃。 最左边位的副本从左边移入。 由于新的最左侧位与前一个最左侧位具有相同的值,因此符号位(最左侧位)不会改变。 因此名称为“符号传播”。

因此,如果您有 32 位的 1,则在应用右移 1 后,您将有 32 位的 1。

它是 32 位宽的事实在规范中, https://tc39.es/ecma262/

6.1.6.1.10 Number::signedRightShift ( x, y )
[...]
4. 返回对 lnum 进行符号扩展右移 shiftCount 位的结果。 传播最高有效位。 结果是一个有符号的 32 位整数。

(同样, <<产生 32 位有符号整数)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM