2011-07-27 37 views
9

我正在实现BER压缩整数的解码,最近我发现了一个奇怪的JavaScript行为,这个行为与大整数的位运算有关。大整数的按位运算

例如为:

var a = 17516032;   // has 25 bits 
alert(a << 7)    // outputs -2052915200 
alert(a * 128)    // outputs 2242052096 
alert(2242052096 >> 16) // outputs -31325 
alert(2242052096/65536) // outputs 34211 

虽然第一个解决方法(乘法代替左移)是可接受的,第二个是不。

为什么会发生?如何忍受它?

+0

我不明白为什么这个师不会被接受? – Guffa

+0

@Guffa我需要一些通用的方法,不仅适用于32位整数。 –

+0

除法不在整数上执行,它在浮点数上执行,所以我不理解你的论点。此外,双精度浮点数只能表示一个53位的整数,所以如果你想解码BER压缩的数字,那就没什么问题了。 – Guffa

回答

7

17516032二进制是00000001000010110100011000000000。左移7将会给你10000101101000110000000000000000。这等于-2052915200two's complement(这是几乎所有的计算机代表负数)。

>>是一个有符号的右移。这意味着最左边的位(它决定了一个数字的符号)将被移到左侧。

例如

1100 >> 2 == 1111 
0111 >> 2 == 0001 

如果你想要做一个无符号的转变(而忽略符号位),使用>>>这将填零位串的左端。

+0

就是这样,谢谢!任何想法为什么左移会产生如此奇怪的结果? –

+0

没问题。编辑我的答案包括这一点。 – tskuzzy

3

按位运算符在32位整数上工作,而乘法和除法在浮点数上工作。

当你移动一个数字时,在操作之前它将从一个浮点数转换为一个32位整数,并在操作之后转换回浮点数。编号2242052096的第32位已设置,因此当转换为32位整数时,它是一个负数。

>>右移运算符不会更改该值的符号,即从左边移入的位具有与符号位相同的值。相反,使用>>>右移操作符来移位零位。

参考:MDN: Bitwise operators

2

(2242052096/65536) == (2242052096 >>> 16)

注不同的移位。

1

Javascript通常将数字表示为(双精度)浮点数。

几乎所有的按位操作都会转换为带符号的32位整数,做它们将要做的任何操作,然后在转换时将结果视为带符号的32位整数。

例外情况是>>>将结果视为无符号的转换回来时为32位整数。

所以:

  • 右移,可向使用>>>,而不是简单地>>工作;
  • a * 128给出了预期的答案,因为它从来没有首先转换为带符号的32位整数 - 它只是一个浮点乘法;
  • a << 7给出了一个意外的答案,因为它被转换为一个有符号的32位整数,然后您将1转换为符号位,导致负32位有符号值。

没有一个<<<,但是如果你想写你左移为转移,你可以使用

(a << 7) >>> 0 

得到预期的答案(该>>> 0有效铸签署32位值转换为无符号的32位值)。

+0

不错。感谢您的解释! –