5

我正在用 javascript 创建一个位掩码。它适用于第 0 位到第 14 位。当我仅将第 15 位设置为 1 时。它产生“ -2147483648”而不是“ 2147483648”的整数值。我可以在这里通过返回硬编码的“”来做一个特殊情况的破解,2147483648但我想知道正确的做法。

示例代码:

function join_bitmap(hex_lower_word, hex_upper_word)
{
    var lower_word = parseInt(hex_lower_word, 16);
    var upper_word = parseInt(hex_upper_word, 16);
    return (0x00000000ffffffff & ((upper_word<<16) | lower_word));
}

当 hex_lower_word 为“0x0”且 hex_upper_word 为“0x8000”而不是 2147483648 时,上述代码返回 -2147483648

4

3 回答 3

3

这是因为 Javascript 的位移操作使用有符号的 32 位整数。所以如果你这样做:

0x1 << 31   // sets the 15th bit of the high word

它将符号位设置为 1,这意味着负数。

另一方面,不是位移,而是乘以 2 的幂,你会得到你想要的结果:

1 * Math.pow(2, 31)
于 2013-02-04T19:41:13.947 回答
2

原因是,您正在设置sign bit...

2147483648是 1 后跟 31 个二进制零 ...

当您进行按位运算时,输出始终是带符号的 32 位数字,这使得第 32 位成为符号位,因此您得到一个负数...

更新

(upper_word * Math.pow(2, 16))

会给积极2147483648的。

但是,你仍然有OR手术,这让我们回到第一方......

于 2013-02-04T19:43:14.853 回答
1

正如前面的答案所解释的,按位运算符是 32 位有符号的。因此,如果在您设置第 31 位的过程中的任何时候,事情都会大错特错。

在您的代码中,表达式

(upper_word<<16) | lower_word)

由于括号,首先计算,并且由于 upper_word 设置了最高位,您现在将有一个负数 ( 0x80000000 = -2147483648)

解决方案是确保您不将 a1移入第 31 位 - 因此您必须在移位之前将高位字的第 15 位设置为零:

mask15 = 0x7fff;
((upper_word&mask15)<<16|lower_word)

这将处理“太大的数字变成负数”,但它不会完全解决问题 - 它只会给出错误的答案!要回到正确的答案,您需要在答案中设置第 31 位,如果在 upper_word 中设置了第 15 位:

bit15 = 0x8000;
bit31 = 0x80000000;
answer = answer + (upper_word & bit15)?bit31:0; 

重写后的函数变为:

function join_bitmap(hex_lower_word, hex_upper_word)
    {
        var lower_word = parseInt(hex_lower_word, 16);
        var upper_word = parseInt(hex_upper_word, 16);
        var mask15 = 0x7fff;
        var bit15 = 0x8000;
        var bit31 = 0x80000000;
        return 0xffffffff & (((upper_word&mask15)<<16) | lower_word) + ((upper_word & bit15)?bit31:0);
    }

不只是一个“硬编码的特殊情况”——大约有 20 亿个。这会照顾所有人。

于 2013-02-04T20:25:46.060 回答