首先,我們要知道Java存儲資料是儲存的補碼,如果對原碼、反碼以及補碼不太懂,可以參考我的另一篇部落格。
1. Java的 與( & ) 運算
所有的邏輯運算都是按位計算的,是以第一步就是先把資料轉成二進制,然後相應位進行 與 運算,具體運算過程可以看下圖中的注釋。
2. Java的 或( | ) 運算
或運算類似,看下圖
3. Java的 非( ~ ) 運算
非運算類似,看下圖。不知道你有沒有看出規律,正數的非運算結果都是本身先加1,然後加個負号;負數的補碼也是本身取絕對值,然後減1。可以去驗證一下 非 運算這個規律。
4. Java的 異或 (^) 運算
異或運算是一個比較奇特的運算原理,首先也是按位運算,然後兩個數相同結果為0,不同為1,即 1^1 = 0,1^0=1,0^1=1,0^0=0。如果學過數字電路這門課的話,你會知道最基本的三種邏輯運算是 與 或 非,異或是可以用這三種基本邏輯運算表示的,那麼怎麼表示呢?如果學過數字電路,是可以畫卡諾圖來用 與 或 非表示異或的,在這裡我們就麻煩點、但是通俗易懂地解釋一下異或怎麼用 與 或 非來表示。
a | b | a&b | a|b | (~a)&b | a&(~b) | (~a)|b | a|(~b) | a^b |
1 | 1 | |||||||
1 | 1 | 1 | 1 | 1 | ||||
1 | 1 | 1 | 1 | 1 | ||||
1 | 1 | 1 | 1 | 1 | 1 |
如表,a和b之間使用基本運算的組合總共有6種,(~a)&(~b)和a&b的效果是一樣,(~a)|(~b)和a|b的效果是一樣,而且~(a&b)和(~a)|(~b)是一樣的,是以隻有上面六種組合。上面6中組合可以怎麼組合得到異或結果呢?因為組合有點多,我們通過代碼來周遊,代碼如下。
class Imple{
static void xor(int[][] arr){
byte f_and = 0;
byte f_or = 0;
for (int k = 0; k < 6; k++) {
for (int l = k+1; l < 6; l++) {
if((arr[k][0] & arr[l][0]) == arr[6][0]){
f_and += 1;
for (int i = 1; i < 4; i++) {
if((arr[k][i] & arr[l][i]) == arr[6][i]){
f_and += 1;
}
}
}
if((arr[k][0] | arr[l][0]) == arr[6][0]){
f_or += 1;
for (int i = 1; i < 4; i++) {
if((arr[k][i] | arr[l][i]) == arr[6][i]){
f_or += 1;
}
}
}
if(f_and == 4){
System.out.println("異或運算可表達為第" + (k+1) + "個表達式和第" + (l+1) + "個表達式相與");
}else if(f_or == 4){
System.out.println("異或運算可表達為第" + (k+1) + "個表達式和第" + (l+1) + "個表達式相或");
}
f_and = 0;
f_or = 0;
}
}
}
static int[][] initArray(){
int[][] com = new int[7][4];
int a;
int b;
for (int j = 0; j < 4; j++) {
a = j/2;
b = j%2;
com[0][j] = a&b;
com[1][j] = a|b;
com[2][j] = (~a)&b;
com[3][j] = a&(~b);
com[4][j] = (~a)|b;
com[5][j] = a|(~b);
com[6][j] = a^b;
}
return com;
}
public static void main(String[] args) {
int[][] arr;
arr = initArray();
xor(arr);
}
}
運作結果如下圖,可知第三個表達式和第四個表達式進行 或 運算可以得到異或的效果,也就是 a^b = ((~a)&b) | (a&(~b)) 現在你可以反驗證。
上面的表達式其實就是課本中對異或的定義,但是上面的公式似乎還不夠簡潔 ,兩個數異或,還有沒有其它表達呢?如下圖
是以我們可以進一步表示異或運算為 a^b = |a - b| (相減取絕對值不是十進制,要先轉換為二進制,然後對應位相減取絕對值)