2

我试图了解 JavaScript 中的按位运算是如何工作的,更具体地说,是如何将按位运算产生的 32 位数字转换回 64 位 JavaScript 数字。在 32 位数字中设置最左边的位以及操作溢出时,我得到了一些奇怪的结果。

例如,使用以下操作:

0x01 << 31

0x80000000如果数字是 32 位长,通常会导致。但是当 JavaScript 将此数字转换回 64 位值时,它会用1结果值填充最左边的 32 位FFFFFFFF80000000

类似地,当左移 32 位,从而溢出一个 32 位整数时,操作如下:

0x02 << 32

数字会溢出,结果值应该是0x00。但生成的 JavaScript 编号是0x02.

JavaScript 是否有任何我不知道的用于按位操作的特定规则?我知道所有按位运算都是使用 32 位整数执行的,并且 JavaScript 数字是 64 位双精度浮点数,但我不明白在两者之间转换时额外填充来自哪里。

4

2 回答 2

1
  1. 按位运算符的结果是有符号的 int32,当它们转换回数字时会传播符号位。

  2. 您不能移动超过 31 位:

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

即,x<<32与 相同x<<0

于 2013-03-20T07:33:38.597 回答
1

在 JavaScript 中,所有数字都使用 53 位表示。JavaScript 使用浮点表示在内部存储所有数字,这意味着整数存储为浮点数(尾数有 53 位)。这篇博客文章是关于这个主题的好读物。

所以用 53 位我们可以表示最大值 2^53 = 9007199254740992。

与 C、C# 等其他语言不同,JavaScript 中不能使用右移和 AND 二进制运算从 53 位数字中提取低 32 位和高 21 位。

原因是当我们对任何数字应用二元运算符时 - JavaScript 首先将该数字转换为 32 位有符号数,应用二元运算并返回结果。这意味着任何高于 32 的位都将被丢弃。

我使用以下方法从正数 <= 2^53 中提取较高(21 位)和较低(32 位)部分。

var bigNumber = Math.pow(2, 53); // 9007199254740992
var bigNumberAsBinaryStr = bigNumber.toString(2); // '100000000000000000000000000000000000000000000000000000'
// Convert the above binary str to 64 bit (actually 52 bit will work) by padding zeros in the left
var bigNumberAsBinaryStr2 = '';
for (var i = 0; i < 64 - bigNumberAsBinaryStr.length; i++) {
    bigNumberAsBinaryStr2 += '0';
};

bigNumberAsBinaryStr2 += bigNumberAsBinaryStr;

var lowInt = parseInt(bigNumberAsBinaryStr2.substring(0, 32), 2);
var highInt = parseInt(bigNumberAsBinaryStr2.substring(32), 2);

要回答有关转换回 64 位的问题,请参见下文:

Assert((lowInt * Math.pow(2, 32) + highInt) === bigNumber);
于 2015-03-03T17:49:42.803 回答