我在javascript中创建一个位掩码。它适用于第0位到第14位。当我只将第15位设置为1.它产生整数值“-2147483648
”而不是“2147483648
”。我可以通过返回第15位的硬编码“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
答案 0 :(得分:3)
原因是因为Javascript的位移操作使用带符号的32位整数。所以,如果你这样做:
0x1 << 31 // sets the 15th bit of the high word
它会将符号位设置为1,这意味着否定。
另一方面,你可以得到你想要的结果而不是比特移位,你可以得到你想要的结果:
1 * Math.pow(2, 31)
答案 1 :(得分:2)
原因是,您正在设置sign bit
...
2147483648
为1后跟31个二进制零...
当您进行按位操作时,输出始终是带符号的32位数,这使得第32位成为符号位,因此您得到负数...
<强>更新强>
(upper_word * Math.pow(2, 16))
会给出正面2147483648
。
但是,你仍然有OR
操作,这使我们回到原点......
答案 2 :(得分:1)
如前所述,按位运算符是32位有符号的。因此,如果在你设置第31位的任何一点上,事情将会出现严重错误。
在您的代码中,表达式
(upper_word<<16) | lower_word)
由于括号,首先评估,并且由于upper_word设置了最高位,因此您现在将具有负数(0x80000000 = -2147483648
)
解决方法是确保不将1
移到第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亿左右。这照顾了所有这些。