32位无符号整数的按位运算?

55

在执行位运算之前,JavaScript会将操作数转换为32位有符号整数。它还使用32位有符号整数进行操作,这意味着结果是一个32位有符号整数。

因为我想要对32位无符号整数进行位运算,所以我想知道是否有一种方法可以使用JavaScript的混淆结果来找到预期的结果。

为了演示我的想法,例如,在C语言中,这是我想要的参考:

unsigned int a = 3774191835u;
unsigned int b = a >> 2;
/* b == 943547958 */

在 JavaScript 中,

 var a = 3774191835;
 var b = a >> 2;
 /* b == -130193866 */

让我们尝试使用不同的操作。在C语言中,

unsigned int a = 1986735448u;
unsigned int b = a << 1;
/* b == 3973470896 */
在JavaScript中,
 var a = 1986735448;
 var b = a << 1;
 /* b == -321496400 */

现在JavaScript使用带符号整数作为操作数进行位运算后,得到的结果与我们在C中对无符号整数进行位运算时得到的结果不同。

我知道有可能解决这个问题,但我不确定如何将JavaScript的结果转换为预期的结果。


对结果进行零填充右移可以解决第二种情况,但不能解决第一种情况。

 var a = 3774191835;
 var b = (a >> 2) >>> 0;
 /* b == 4164773430 */

 var a = 1986735448;
 var b = (a << 1) >>> 0;
 /* b == 3973470896 */
3个回答

122

你只需要遵循以下规则:

  1. 对于位运算的结果,一定要加上 >>> 0 ,这样结果才会被解释为无符号数。
  2. 不要使用 >> 运算符。如果最高位是1,则它将尝试保留符号,并在左侧引入1。请始终使用 >>>

举例:

C:  (3774191835 >> 2) | 2147483648
js: (3774191835 >>> 2 | 2147483648) >>> 0

C:  1986735448 << 1
js: (1986735448 << 1) >>> 0

C:  3774191835 & 4294967295
js: (3774191835 & 4294967295) >>> 0

只有当最后一个操作是>>>时,>>> 0不是必需的。


3
+1 并且这里也有一个很好的描述:>>> 零填充右移 @ MDN - Stano
1
哦,Javascript,为什么你要如此奇怪? - Radvylf Programs

3

虽然不美观,但是:

var a = 1986735448;
var b = (a << 1) >>> 0;
/* b = 3973470896 */

1
@Delan Azabani,这只是因为>>>返回一个无符号值。移位操作在有符号或无符号情况下都执行相同的操作,只是Javascript引擎对位的解释不同。因此,在多个位运算之后,例如((a | 2) << 1) >>> 0,您只需要执行一次>>> 0即可。 - Paul
我理解这一点;然而,在JavaScript中(3774191835 >> 2) >>> 0返回的是4164773430,这是错误的。我不太确定该怎么做。 - Delan Azabani

1
JavaScript通过提供两个位移操作符>>>>>来解决这个问题。你需要使用>>>进行位移而不改变符号位。

不,它并没有。JavaScript仍然将操作数转换为32位有符号整数,并将操作的结果作为32位有符号整数返回。请查看我的更新答案,显示这与位移没有特定关系。 - Delan Azabani
当我执行alert(3774191835>>>2)时,它给出了943547958,所以我猜在赋值中发生了一些事情? - jswolf19
那个特定的情况也许可以通过使用无符号右移来解决,但其他运算符呢? - Delan Azabani
似乎@PaulPRO有一个答案 ^_^ - jswolf19
对于加、减、乘,不必考虑符号,结果(二进制位模式)相同。对于除法,您可以使用(a >>> 0)/ b。 - Jochen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接