Java的移位运算
前言
計算機支持兩種移位運算,假設操作數為x,移動的位數為k,則向左移位是 x << k,向右移位是 x >> k。左移位會對輸入的操作數舍棄最高的k位,并在右端補k個0。而右移位運算卻分為兩種情況,分別是邏輯右移和算術右移(也叫無符號右移和符號右移),在邏輯右移中,會對操作數舍棄最低的k位,并在左端補k個0,在算術運算中,則對操作數舍棄最低的k位,并在左端補k個最高有效位的值。
對于有符號數來說,最高位有效值是不同的,所以邏輯右移和算術右移將產生不同的效果,而C語言并沒有明確定義有符號數該使用哪種類型的右移,雖然兩種右移都可以,但是現在幾乎所有的編譯器/機器組合都會對有符號數使用算術右移。而Java比C強大的一個地方在于它對右移有明確的定義,規定 x >> k 使用算術右移, x >>> k 使用邏輯右移。
本文將通過幾個實際的例子,并手動計算二進制執行過程,來探究當操作數分別為正數和負數時,Java的移位運算是怎么實現的。
左移位運算
左移運算也相當于做乘法運算,乘積因子為 2^k。例如,我們執行149 << 4,相當于執行了 149*16 = 2384。
1)正數左移位運算
System.out.println (149 << 4); System.out.println (Integer.toBinaryString ( 149 << 4 )); 2384 100101010000149 << 4 的計算過程如下:
輸入:? ? ? ? ? ? 149
轉為二進制: 10010101
展開32位:? ? ? ?00000000 00000000 00000000 10010101
丟棄最高4位:? 0000 00000000 00000000 10010101
右端補4個0:?0000 00000000 00000000 10010101 0000
忽略符號位: 10010101 0000
轉為十進制: 2384
可以看出,我們計算過程的最后兩步和程序打印效果完全一致。
2)負數左移位運算
System.out.println (-149 << 4); System.out.println (Integer.toBinaryString ( -149 << 4 )); -2384 11111111111111111111011010110000-149 << 4 的計算過程如下:
輸入:? ? ? ? ? ? -149
轉為二進制: 11111111 11111111 11111111 01101011? ? ? ? ?(ps: 絕對值二進制取反再加1。)
丟棄最高4位:? 1111 11111111 11111111 01101011
右端補4個0:?1111 11111111 11111111 01101011 0000
以上是個負數二進制,現要轉成十進制,按照以下三步進行:
? ? ? ? ? ? ? ? ? ? ? ?1111 11111111 11111111?01101010?1111? ? ? (減1)
? ? ? ? ? ? ? ? ? ? ? ?0000 00000000 00000000 10010101 0000(取反)
? ? ? ? ? ? ? ? ? ? ? -10010101 0000? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(忽略符號位,并添負號)
轉為十進制: -2384
可以看出,我們計算過程的第4步和最后一步的計算結果和程序打印效果完全一致。
右移位運算
右移運算也相當于做除法運算,被除數為 2^k。例如,我們執行149 >> 4,相當于執行了 149/16 = 9。
1)正數右移運算
Java的基本類型數據都是有符號數,最高位為1表示負數,最高位為0表示正數。所以對于正數來說,邏輯右移和算術右移沒有任何區別,因為都是在左端補0。
System.out.println (149 >> 4); System.out.println (Integer.toBinaryString ( 149 >> 4 )); System.out.println (149 >>> 4); System.out.println (Integer.toBinaryString ( 149 >>> 4 )); 9 1001 9 1001149 >> 4 計算過程:
輸入:? ? ? ? ? ? 149
轉為二進制: 10010101
展開32位:? ? ?00000000 00000000 00000000 10010101
丟棄最低4位:00000000 00000000 00000000 1001
左端補4個0:? 0000 00000000 00000000 00000000 1001
忽略符號位:? 1001
轉為十進制:? 9
149 >>> 4 的計算過程和上面完全一樣,左端都是補4個0,所以打印效果當然是一致的。
2)負數右移運算
當輸入的數據是負數,此時邏輯右移和算術右移將產生較大區別。由于負數高位是1,所以邏輯右移和算術右移在左端分別補0和1。
System.out.println (-149 >> 4 ); //負數的算術右移 System.out.println (Integer.toBinaryString ( -149 >> 4 )); System.out.println (-149 >>> 4 ); //負數的邏輯右移 System.out.println (Integer.toBinaryString ( -149 >>> 4 )); -10 11111111111111111111111111110110 268435446 1111111111111111111111110110a)-149 >> 4 計算過程(負數的算術右移):
輸入:? ? ? ? ? ?-149
轉為二進制:? ?11111111 11111111 11111111 01101011? ? ? ? ?(ps: 絕對值二進制取反再加1。)
丟棄最低4位: 11111111 11111111 11111111 0110
左端補4個1:1111 11111111 11111111 11111111 0110
相應十進制:? -0000 00000000 00000000 00000000 0101? ?(ps: 減1,取反,添負號。)
轉為十進制:-10
可以看出,我們第4步和第6步運算結果和代碼打印的前兩行完全一致。
b)-149 >>> 4 計算過程(負數的邏輯右移):
輸入:? ? ? ? ? ? ???-149
轉為二進制:? ? 11111111 11111111 11111111 01101011? ?? ? (ps: 絕對值二進制取反再加1。)
丟棄最低4位:? 11111111 11111111 11111111 0110
左端補4個0: 0000 11111111 11111111 11111111 0110
轉為十進制: 268435446
可以看出,我們第3步和第5步運算結果和代碼打印的后兩行完全一致。
總結
- 上一篇: 天堂2芙蕾雅单机版mysql闪退_【图片
- 下一篇: java右移位_Java移位运算