javascript - 我需要 ((2^32-1) << 0) 的解释(和可能的解决方法)导致 Javascript 中的 -1
问题描述
编辑:最后的解释。
我试图使用 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
也是完全可以预料的。有符号的右移>>
是 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 位有符号整数)
推荐阅读
- javascript - 未捕获的类型错误:无法在笔记网站中读取 HTMLButtonElement 处的 null 属性“推送”
- excel - 我在 Excel VBA 表单中创建动态创建的选项按钮(单选按钮)时遇到问题
- java - 让玩家向鼠标指针坐标射击子弹
- java - 如何解决Kafka消息生产者NoSuchMethodError org.apache.kafka.common.security.ssl.SslFactory.sslEngineBuilder()
- python - 在各种服务之间共享 python 代码的最佳方式是什么?
- appium - 无法使用 webview 中的 setconnection 断开互联网连接
- spring-boot - 如果一个线程已经在spring boot rest api中开始处理,如何响应客户端
- twilio - 如何在回调函数中获取 Flow SID
- security - API 和数据库访问控制架构
- node.js - 在获取数据 react-Native 中实现循环