2011-07-27 68 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

不錯。感謝您的解釋! –