編程語言的巧妙之處-位運算

如何不使用+,-運算符號計算兩個數之和?

在編程語言中除了+,-等符號運算,還有位運算.

^,異或,相同爲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!!!!!!!!!!!!!!!!!!!!太難了,哈哈哈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章