Java中處理二進制移位

我相信,這篇文章讀起來會至關有趣。python

文章中編程語言是Java,用Java的緣由:
第一,Java不作數據溢出校驗,這樣咱們能夠忽略溢出異常;
第二,Java普及率比較高,就像是python或shell,幾乎人人都會吶。shell

肯定一些位運算符:
|   按位或   1001 | 1010 = 1011  (口訣,有真則真 似or邏輯)
^  按位異或  1001 ^ 1010 = 0011  (口訣,不等則真)
&  按位與   1001 & 1010 = 1000  (口訣,同真則真 似and邏輯)
~  按位取反  ~1001 = 0110 (這條沒口訣)
>> 右移 或 位移除法
<< 左移 或 位移乘法 編程

如下是一個將十進制數轉化爲二進制數顯示爲字符串的方法,爲了方便我以後的測試而作此轉換方法:dom

 1     public static String integerToBinaryString(int input) {
 2         char[] charr = new char[32];
 3         int k = 1;
 4         boolean isTrue;
 5         for (int i = 32 - 1; i >= 0; i--) {
 6             isTrue = (k & input) == k;
 7             charr[i] = isTrue ? '1' : '0';
 8             k = k << 1;
 9         }
10         return new String(charr);
11     }

此處我沒有使用Integer.toBinaryString(n),是由於這個返回會忽略前面的全部零狀況,二進制數據長度很難對齊,給分析帶來很大難度。因此就本身作了integerToBinaryString方法,注意此方法從最低位開始計算每一個位的值,由於我這裏用Java寫的測試,而Java是不支持無符號(unsigned)類型數據,有符號和無符號數據在 << 時規則是相同的,可是 >> 時,有符號和無符號會因最高位爲符號位的限制,產生一些規則不一樣的問題,以後作個測試說明。編程語言

調用如下方法:測試

1         int a = 9;// 1001
2         int b = 10;// 1010
3         System.out.println(integerToBinaryString(a | b));
4         System.out.println(integerToBinaryString(a ^ b));
5         System.out.println(integerToBinaryString(a & b));

輸出結果:spa

以上結果用來驗證我說的三個口訣,可見口訣正確。

code

請用如下代碼進行測試位移:blog

 1         int a = 0x12345678;
 2         Scanner scanner = new Scanner(System.in);
 3         while (true) {
 4             System.out.println(integerToBinaryString(a));
 5             System.out.println(Integer.toHexString(a) + "\t" + a);
 6             System.out.print("輸入:");
 7             String in = scanner.next();
 8             if (in.startsWith(">")) {
 9                 a >>= 1;
10             } else if (in.startsWith("<")) {
11                 a <<= 1;
12             } else if (in.startsWith("reset")) {
13                 Random rand = new Random();
14                 a = rand.nextInt();
15             } else {
16                 System.out.println("輸入 '>'、'<' 或 'reset',請繼續...");
17             }
18         }

 

控制檯操做:圖片

 

由上位移可見,當a的最高位爲1時(圖片第四步驟),進行>>操做,最高位不會被0取代,繼續進行操做:

 

經過<<操做將0推到最高位後,而後進行>>操做,最高位會被0覆蓋。
以上簡單的測試,只是爲了解釋一下在有符號位狀況下,左移和右移操做的稍許不一樣之處,固然無符號狀況下,最高位爲1時,進行>>操做,最高位會被0覆蓋。這是爲何呢?仍是找一些官方解釋比較有說服力。

 

這本教材是我大學裏的必修課程,177頁中位移除法對此有詳細說明。

 

固然這個說法仍是過於粗糙了,當了解了運算器對有符號位運算原理,或許就能豁然開朗了。
我仍是說一些比較好玩的東西吧。
補碼和反碼

1 int b = -20;
2 int bb = ~b;
3 int bbb = ~b + 1;
4 System.out.println(integerToBinaryString(b));
5 System.out.println(integerToBinaryString(bb));
6 System.out.println(integerToBinaryString(bbb));

補碼bbb和反碼bb

 

做爲反碼好理解點,就是按位翻轉;
補碼這東西老是讓人云裏霧裏,有點琢磨不透,其實在二進制運算中,補碼就是源碼的模。
二進制中定義:正數補碼是它自己,負數補碼就是它的模了。

有了這層意義,不妨定義一個運算的最大值爲13a=7,b=-2a+b==? 固然用簡單運算的確能求出值爲5可是我要以如下方法求值bb == b%13 == 11這裏要能理解 bb == b,不然很難解釋下去了。那麼 a+b == a+bb == 7+11 == 18所以時18大於13,超出部分會溢出,因此a+b == 18%13 == 5跟我想固然理解 a+b == 7 +(-2) == 7-2 == 5 的值徹底吻合此時,無符號位移位除法空位設置0就很好理解,由於無符號的數必定都是非負數,其補碼就是它自己;有符號位移位除法空位被設置爲1估計也就好理解了,是爲了方便此負數轉補碼時空位轉爲0,固然這只是其中一點緣由,也許深入瞭解運算器構造和原理,對此問題會有個更好的認識。

相關文章
相關標籤/搜索