位操作

劉二郎發表於2018-07-13

位操作應該說從學C的時候就接觸過,一開始以為沒什麼大用,但是現在在不斷的學習和有了工作經驗之後,發現這個東西真是個好東西,很多便捷操作都可以藉助它來實現,並且很有效率。

參考文章:

位操作基礎篇

《演算法心得》參考的不多,裡面很底層。

位操作基礎
符號描述規則
&按位與兩個位都是1,結果才是1(1&1=1;1&0=0)
|        按位或兩個位都是0,結果才是0(1&0=1;0&0=0)
^按位異或兩個位相同為0,相異為1(1&0=1;1&1=0)
~按位取反0變1,1變0(單目操作符,優先順序高
<<左移左移若干位,丟棄高位,低位補0
>>右移右移若干位;無符號數,高位補0,有符號數,算數右移(補符號位)或者邏輯右移(補0)








1. 針對右移,需要簡單擴充套件一下。

邏輯右移:不考慮符號位,右移一位,左邊補0;

算術右移:考慮符號位,右移一位,若符號位為1,左邊補1,否則補0。(可以進行有符號位的除法,右移n位=除2的n次方)。

8的二進位制:1100 1101。

邏輯右移:[0]110 0110。

算術右移:[1]110 0110。

2. 符合操作符

&=、|=、^=、<<=、>>=。

常用位操作

1.判斷奇偶

奇數偶數只要根據最後一位是1還是0就能判斷出,傳統的操作比如(i % 2 == 0)來判斷,位操作裡可以用&來代替。實際測試程式碼來看,確實時間花費要少許多。

        for(int i = 0; i < 101 ; i++){
            if( (i & 1) == 0){
                System.out.println(i);
            }
        }
2.交換2數

這個我在很早的面試寶典裡就看見過了,心想,何必這麼秀呢。

        if(a != b){

            a ^= b;
            b ^= a;
            a ^= b;

        }

異或運演算法則如下:

1. a ^ b = b ^ a;

2. a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;

3. a ^ b ^ a = a ^ a ^ b = 0 ^ b = b(a和自己異或等於0,0和任意數異或還等於自己);

通過以上三個法則就能來推到兩數交換了,很簡單其實。

3.變換符號

這個其實沒什麼說頭,就是當初學習正數負數的二進位制操作時所說的取反+1操作的程式碼實現。

~a + 1
4.求絕對值

主要看當前的數是正數還是負數來決定,能決定的就是符號位,因此先右移得到,高1位,然後判斷是0還是1,再做取反+1操作即可。

        int i = a >> 31;
        return (i == 0) ? a : ~a + 1;

但是比較苛刻的用法此處還能優化,,比如在第一點裡的異或規則我們知道,a ^ 0 = a ,而 a ^ -1 = ~a(任何數和-1異或相當於取反操作,因為-1的二進位制碼是1111 1111,很特殊)。

加上我們i的取值在a右移31位後剛好是0或者-1,所以可以寫成下面這種。

        int i = a >> 31;
        return ((a ^ i) - i);
        //i 為0時 return ((a ^ 0)-0);
        //i 為-1時 return ((a ^ -1) - (-1)) == (~a + 1);
5判斷一個數是不是2的冪

我們發現2的冪的數的二進位制都是最高位是1,其餘都是0,那麼如何判斷這種呢?可以將高位1變成0,其餘變成1,按位與操作,這樣,如果還是0,說明是2的冪,如果不是0,說明不是。

  return i & (i-1) && (i != 0);

相關文章