背景
為什麼要做js位運算呢?
- 因為最近在學習hash算法,裡面用到了大量的位運算
- 另外網上也找了很多資料,但大都比較片面,沒有說明特殊情況時的處理,換幾組數據計算結果就出錯。
重溫整數
ECMAScript 整數有兩種類型,即:
- 有符號整數(允許用正數和負數)
- 無符號整數(只允許用正數) 在 ECMAScript 中,所有整數字面量默認都是有符號整數,這意味着什麼呢?
有符號整數使用 31 位表示整數的數值,用第 32 位表示整數的符號,0 表示正數,1 表示負數。
數值範圍從 -2147483647 到 2147483647。
位運算會把二進制數限制在32位,超出部分會被捨棄
調試位運算常用的幾個方法
toString(2)
轉換成2進制字符串
var a = 1732584193;
a.toString(2); // 1100111010001010010001100000001parseInt(‘11001’, 2)
將2進制字符串轉換成10進制數
parseInt('11001', 2) // 25padStart(32, ‘0’)
字符串總長度,左邊不足位數補0
'1100000001'.padStart(32, 0) // 00000000000000000000001100000001源碼、反碼、補碼
源碼
將數字轉換成的2進制數, 最左邊表示符號位,1負數,0正數
5 源碼: 0101
-10 源碼:11010反碼
正數的反碼與其原碼相同
負數的反碼,除符號位外,其他位取反
5
源碼:0101
反碼:0101
-10
源碼:11010
反碼:10101補碼
正整數的補碼與其原碼相同
負整數的補碼,取反碼+1
5
源碼:0101
補碼:0101
-10
源碼:11010
補碼:10110ok,現在開始正題
位運算符
- 非(~)
- 與(&)
- 或(|)
- 異或(^)
- 帶符號左移(<<)
- 帶符號右移(>>)
- 無符號右移(>>>)
位運算符:非(~)
運算步驟:
- 將該數字取負數
- 然後減1
~25 // -26過程:
- 25取負:-25
- 減1:-26
~1 // -2
~-1 // 0
~100 // -101
~-100 // 99位運算符:與(&)
運算步驟:
- 把兩個數轉換成2進制補碼
- 相同位置進行比較(同為1,結果為1,否則為0)
- 如果計算結果是負數,還要再做補碼處理
如果位數不夠,正數左邊補0,負數補1
正正運算
10 & 3 // 2過程:
- 10 補碼:1010
- 3 補碼:0011
- 結果:0010,即 2
正負運算(1)
14 & -13 // 2過程:
- 14 補碼:01110(補一位符號位)
- -13 源碼:11101,補碼:10011
- 與運算:00010,即 2
正負運算(2)
88 & -19 // 72過程:
- 88 補碼:01011000(補一位符號位)
- -19 源碼:110011,補碼:101100
- 01011000 & 101100
- 負數(101100)位數不夠,左邊補1,即11101100
- 也就是 01011000 & 11101100
- 結果為:01001000,即:72
負負運算
-12 & -5 // -16過程:
- -12 補碼:10100
- -5 補碼:11011
- 與運算:10000
- 結果為負,再取一次補碼: 110000:-16
練習
3 & 7
-21 & 16
-271733879 & -1732584194
1125899778533470 & 812930
20 & 0xF
48192342 & 0xFFFF位運算符:或(|)
運算步驟:
- 把兩個數字轉換成2進制補碼
- 相同位置進行比較(有一個是1,結果即為1)
- 如果計算結果是負數,還要再做補碼處理
正正運算
10 | 3 // 11過程:
- 10 源碼:1010
- 3 源碼:0011
- 結果:1011,即 11
正負運算
10 | -3 // -1過程:
- 10補碼:01010
- -3補碼:11101
- 或運算:11111
- 結果為負,再取碼:10001,即:-1
負負運算
-15 | -21 // -5過程:
- -15 補碼:110001
- -21 補碼:101011
- 或運算:111011
- 結果為負再取補碼:10101,即:-5
練習
15 | 20
40 | -14
-271733879 | 1732584193
(-271733879 & -1732584194) | (~-271733879 & 271733878)位運算符:異或(^)
運算步驟:
- 把兩個數轉換成2進制補碼
- 相同位置進行比較(必須是0和1或者1和0,結果才為1)
- 如果結果為負,再取補碼
正正異或
10 ^ 3 // 9過程:
- 10 補碼:1010
- 3 補碼:0011
- 結果:1001,即 9
正負異或
10 ^ -3 // -9過程:
- 10 補碼: 01010
- -3 補碼:11101
- 異或運算:10111
- 結果為負,再取補碼:11001,即-9
負負異或
-10 ^ -3 // 11過程:
- -10 補碼:10110
- -3 補碼:11101
- 異或運算:01011,即:11
練習
5 ^ 8
-10 ^ 9
-13 ^ -20
-271733879 ^ -1732584194 ^ 271733878位運算符:帶符號左移(<<)
運算步驟:
- 把數字轉換成2進制補碼
- 左移指定位數,右邊補0
- 如果結果未負數,再取補碼
超過32位的部分捨棄
正數左移
1 << 2 // 補碼:00000001 左移2位, 即 00000100,結果為:4
5 << 3 // 補碼:00000101 左移3位, 即 00101000,結果為:40 可以看出,正數帶符號左移,即 a << n,其實是 a * 2的n次冪
負數左移
-3 << 4- -3 補碼:101
- 左移4位 1010000
- 標誌位為負,取補碼:1110000,即-48
-6 << 3 // 1010 << 3 等於 1010000,取補碼,1110000 即:-48
-11 << 4 // 10101 << 4 等於 101010000,取補碼,110110000 即:-176邊緣情況
情況1:正數變負數
1732584193 << 2 // -1659597820計算過程
- 1732584193轉換成2進制源碼:1100111010001010010001100000001(31位)
- 左移2位,補2個0:110011101000101001000110000000100(33位)
- 移除左邊多餘的1位:10011101000101001000110000000100(32位)
- 變為負數,取補碼:11100010111010110111001111111100
- 即:-1659597820
情況2:負數變正數
-1732584193 << 2 // 1659597820計算過程
- -1732584193轉換成2進制:11100111010001010010001100000001(32位)
- 負數,取補碼:10011000101110101101110011111111(32位)
- 左移2位:1001100010111010110111001111111100(34位)
- 多餘部分捨棄:01100010111010110111001111111100(32位)
- 符號位為正,無需再補碼,即:1659597820
練習
1 << 32
1 << 33
1 << 40
2147483648 << 2
1732584193 << 6位運算符:帶符號右移(>>)
運算步驟:
- 取數字二進制補碼
- 右移指定位數,左邊補位與符號位一致
- 多餘位被捨棄
- 如果計算結果為負,再取補碼
正數右移
5 >> 1 // 0101 右移1位 0010,即 2
1 >> 2 // 0001 右移1位 0000,即 0正數右移比較簡單,移出的內容直接捨棄即可,左邊用0補充
負數右移
-5 >> 2 // -2分析:
- -5 補碼:1011
- 右移2位:1110
- 結果為負,取補碼:1010,即-2
練習
5 + 64 >> 9
1732584193 >> 4位運算符:無符號右移(>>>)
運算步驟:
- 把數字轉換成32位2進制補碼
- 連同符號位,右移動指定的位數
- 向右被移出的位被丟棄,左側用0填充
因為符號位變成了 0,所以結果總是正的
正數右移
正數時候 >> 和 >>> 結果是一樣的
5 >> 2 // 101 右移2位 001 即:1
5 >>> 2 // 101 右移2位 001 即:1負數右移
-5 >>> 2 // 1073741822過程:
- -5 源碼: 10000000 00000000 00000000 00000101
- 補碼:11111111 11111111 11111111 11111011
- 右移兩位:00111111 11111111 11111111 11111110
- 轉換成十進制即為:1073741822
問題:為什麼這個要補滿32位,而之前的運算都沒有?
因為之前的運算,正數補的都是0,負數雖然補1,但計算後要做補碼,補位的數最終不影響計算
而無符號右移,則會影響運算。所以需要補全
練習
-23 >>> 2
45678765 >>> 31關於位運算的核心思路
- 運算前要取補碼
- 運算結果導致負數,再取一次補碼
以上內容都是個人收集、以及多次嘗試整理的。
因為網上看到的很多文章計算方式都不對,雖然舉的例子沒問題,但換機組數字就計算錯誤。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/226027.html
微信掃一掃
支付寶掃一掃