如何不使用+,-運算符號計算兩個數之和?
在編程語言中除了+,-等符號運算,還有位運算.
^,異或,相同爲0,不同爲1.
比如 : 2^3
0 0 1 0
0 0 1 1
_______
0 0 0 1 (相同出0,不同出1,結果=1)
2^3 = 1;
&,與,同1出1,有0爲0.
比如 2&3
0 0 1 0
0 0 1 1
_______
0 0 1 0 (同1出1,有0出0,結果爲2)
2&3 = 2;
<<,向左位移.
比如 2<<1
0 0 1 0
_______
0 0 1 0 0 (左移1位,低位用0補齊,結果是4)
2 << 1 = 4;
由於正數的源碼,補碼,反碼都一樣,相對簡單,來分析一下如果是負數的左移
比如
-3 << 2
在計算機中所有數字都以補碼存儲:
所以對於數字-3有,
源碼: 10000000 00000000 00000000 00000011;
反碼: 11111111 11111111 11111111 11111100; (符號位不變,其他位按位取反)
補碼: 11111111 11111111 11111111 11111101; (最低位+1,-3在計算機中的實際存儲)
左移2位後的補碼:
11111111 11111111 11111111 11110100; (左移2位,低位用0補齊,最高位爲符號位)
反碼: 11111111 11111111 11111111 11110011;(補碼-1)
源碼: 10000000 00000000 00000000 00001100; (結果爲-12)
-3 << 2 = -12;
>>,向有位移.
比如 2>>1
0 0 1 0
_______
0 0 0 1 (右移一位,結果爲 1)
2 >> 1 = 1;
比如-3 >> 2
我們已經知道-3的補碼爲:11111111 11111111 11111111 11111101;
右移兩位:11111111 11111111 11111111 11111111; (負數符號位不變,右移兩位,高位用1補齊)
反碼:11111111 11111111 11111111 11111110; (補碼-1)
源碼:10000000 00000000 00000000 00000001; (反碼取反,結果等於-1)
-3 >>2 = -1;
>>>無符號右移.
比如 2>>>1
0 0 1 0
_______
0 0 0 1 (無符號左移1位,結果爲1)
2>>>1 = 1;
>>>與>>唯一的不同是它無論原來的最左邊是什麼數,統統都用0填充。(包括負數)
比如 -3 >>> 5;
已知-3的補碼爲:11111111 11111111 11111111 11111101;
無符號右移5位:00000111 11111111 11111111 11111111; (高位用0補充)
源碼:00000111 11111111 11111111 11111111; (最高位是0表示正數,正數原反補碼一致)
結果爲:
1*2的26次方+ 1*2的25次方 +....+1*2的0次方 = 134217727;
-3>>>5 = 134217727;
那麼基本的位運算現在我們都已經瞭解了.來看前面提出的問題:
比如 2 + 3 = 5;
而我們知道 (2+3也可以使用位運算)
0 0 1 0
+ 0 0 1 1
_______
0 1 0 1 (結果等於5)
而 2^3
0 0 1 0
0 0 1 1
_______
0 0 0 1 (可以表示爲2+3逐位相加後除進位外剩下的數字 1+0=1=1^0)
而 2&3
0 0 1 0
0 0 1 1
_______
0 0 1 0 (可以表示爲2+3逐位相加後的進位1+1=0(進位1=1&1),只不過結果應該左移1位,即 2&3<<1)
0 1 0 0 (左移一位)
然後將異或的結果和左移一位後的與結果相加
0 1 0 0
+ 0 0 0 1
___________
0 1 0 1 (結果等於5,此時的加法重複上面的運算 即 2+3 = 2&3<<1+2^3 = 4&1<<1 + 4^1)
什麼時候應該結果重複運算?
當進位結果等於0時,運算結束,得到結果:
0 1 0 0
0 0 0 1
___________
0 0 0 0 (4&1<<1 = 0 結束,此時4^1 = 5,所以3+2 = 5)
java代碼如下
int sum (int a, int b){
int sum = a^b;
int cur = a&b<<1;
if(cur==0)return sum;
retturn (sum,cur);
}
最後我們終於完成了3+2=5!!!!!!!!!!!!!!!!!!!!太難了,哈哈哈