位運算符:按位與(&),按位或(|),按位異或(^),取反(~)左移()

       數據在內存中是以二進制的形式存放的,計算機存儲數據的最小單位是位(bit),一個二進制位可以表示兩種狀態(0和1),一個字節通常由8位二進制位組成。C語言支持按位運算,按位運算也就是對字節或者字中的實際位進行操作。


       C語言的位運算符包括:

運算符 含義
& 按位與
| 按位或
^ 按位異或
~ 取反
<< 左移
>> 右移

與運算符
       按位與運算符“&”是雙目運算符,只有兩個二進制位均爲1時結果才爲真;
按位與真值表

a b a&b
0 0 0
0 1 0
1 0 0
1 1 1

      整形數據在內存中存放的是二進制的補碼,所以整形數據的運算即是其二進制補碼的運算;按位與運算:以89和38爲例:

按位與運算
      按位與的主要用途就是清零(即:把1置爲0),若要將原數中爲1的位置爲0,只需將與其進行與操作的數對應位置0即可,如上邊的例子,要將89二進制中的1置0,我們需要找一個89二進制位中1的對應位置爲0的數(38)與其相與;

     如何判斷一個數是2^n;通過按位與操作可以方便的實現判斷,我們知道,一個數若爲2^n,那麼其二進制序列中只有一個1,其餘位皆爲0(正數)。假設一個數爲n,那麼它與n-1相與,會消除一個1,所以我們只需讓n與n-1相與,如果其結果爲0,那麼這個是就是2^n,C語言實現代碼爲:

#include <stdio.h>
#include <Windows.h>

int main()
{
    int a;
    scanf("%d", &a);

    if ((a&(a - 1)) == 0)
    {
        printf("Y\n");
    }
    printf("N\n");
    system("pause");
    return 0;
}

     ‘==’運算符的優先級高於爲運算符,if ((a&(a - 1)) == 0)括號不能省略,不然程序執行會直接跳過if 語句,輸入所有的數都會打印‘N’;

例:求一個整數的二進制序列中有多少位1;

C語言源代碼:

//求一個整數的二進制序列中1的個數

/*按位與的主要用途就是清零,一個數n與其n-1相與會消除一個1,即把1變成0,
所以求一個數二進制序列中1的個數,只需讓這個數n一直與n-1相與,直到這個
數值爲0,可以設置一個計數器count,每相與一次,計數器count++即可,當這
個數的值變爲0時,返回count的值即爲該數二進制序列中1的個數*/

#include <stdio.h>
#include <Windows.h>

int main()
{
    int num = 0;
    int count = 0;
    scanf("%d", &num);
    while (num)
    {
        num = num & (num - 1);
        count++;
    }
    printf("%d\n", count);
    system("pause");

    return 0;
}

測試結果:輸入:5 輸出:2 輸入:-5 輸出:31


或運算符

     按位或’|’運算符也是雙目運算符,參與運算的兩個數各位相“或”,只要其中有一個二進制位值爲1,結果就爲真。
按位或真值表

a b a|b
0 0 0
0 1 1
1 0 1
1 1 1

      按位或運算,以75和63(均爲int型數據)爲例:
這裏寫圖片描述
      如果要將一個數的某幾位置爲1,只需要與這幾位二進制序列是1的數進行或操作即可;上面的例子:75與63(或6位都爲1)相與,其結果後六位都爲1,同理要是5位全爲1,只需與31按位或即可,要使其後n位變爲1,需要與2^-1按位或即可。


異或運算符
      按位異或“^”是雙目運算符,參與運算的兩個數對應的二進制位相異或,當對應的兩個二進制位相異時,結果爲1,否則結果爲0;

按位異或真值表:

a b a^b
0 0 0
0 1 1
1 0 1
1 1 0

      按位異或運算,以198和255(數據皆爲int型)爲例:
這裏寫圖片描述
      從上邊的例子我們可以看出異或操作可以使一個二進制序列特定位翻轉(0變爲1,1變爲0);如:198原碼的後8位數爲:11000110與255(原碼後8位11111111)相與結果爲00111001,同理:若要使一個數的二進制序列的後n位翻轉,只需將這個數與後n位全是1的數相異或即可;

例如:從鍵盤輸入一個數,實現使其低四位翻轉,即0變成1,1變成0,輸出其結果

C語言代碼:

/*按位異或的一個作用就是實現特定位的翻轉,將一個數的後n位
翻轉,只需將這個數與後n位全是1的數相異或即可,題目要求輸入
一個數,將其後四位翻轉,只需將這個數與15相異或即可*/


#include <stdio.h>
#include <Windows.h>

int main()
{
    int a;
    scanf("%d", &a);
    int b = 15;
    printf("%d", a^b);
    system("pause");
    return 0;
}

輸入:145 輸出:158
可以簡單的運算一下:
145的原碼後8位爲:10010001 後四位翻轉後爲:10011110;其值爲:2^7+2^4+2^3+2^2+2^1 = 128 + 16 + 8 + 4 +2 =158;

      使用異或運算符還可以實現:不使用臨時變量交換兩個數的值:

C語言代碼:

//交換兩個數的值,不使用臨時變量

#include <stdio.h>
#include <Windows.h>

int main()
{
    int a = 4;
    int b = 3;
    a = a ^ b;
    b = b ^ a;
    a = a ^ b;

    printf("a = %d\t b = %d\n", a, b);
    system("pause");
    return 0;
} 

運行結果:a = 3 b = 4


取反運算符

     取反運算符爲單目運算符,具有右結合性,取反運算符是對參與運算的數的二進制位按位取反,即0變爲1,1變爲0(包括符號位),不可簡單的理解爲一個數取反後的值爲其相反數;
     例如隨便給一個數:45(int 型數據)對其取反;

這裏寫圖片描述
在以上運算過程中其符號位不變。


左移運算符

     左移運算符是雙目運算符,作用是把”<<”左邊的運算數的各二進制位全部左移若干位,由”<<”右邊的數指定其移動的位數,左移過程中高位丟棄,低位補0;
     例如:int a=45;int b =a<<2;
這裏寫圖片描述
     那如果是負數呢?原理是一樣的,要注意的是操作的對象是補碼,移位完成後,要將其轉化爲原碼,然後其值;
     例如:int a=-45;int b =a<<2;
這裏寫圖片描述
     實際上,左移一位相當於該數乘以2,將一個數左移兩位相當於該數乘以4,這種情況僅限於移出位不含1的情況;


右移運算符

     右移運算符是雙目運算符,作用是把”>>”左邊的運算數的各二進制位全部右移若干位,由”<<”右邊的數指定其移動的位數;
     例如:int a=45;int b =a<<2;
這裏寫圖片描述
     在進行右移時對於有符號數要注意符號位的問題。當爲正數時,最高位補0;而爲負數時,最高位補0還是補1,取決於編譯系統的規定。補0的稱爲邏輯右移,補1的稱爲算術右移,當在我們運算是採用的是算術右移,即:最高位補符號位1;


簡單小結

  • 位運算符包括:按位與、按位或、按位異或、取反、右移和左移 ;
  • 除‘~’取反外,其餘皆爲雙目運算符,結合方向均爲自左向右;
  • 按位與,只有兩個二進制位均爲1時結果才爲1,其餘皆爲0,按位與可以實現二進制序列指定爲清0,(n)&(n-1),每次可以清0一次,即把一個1變爲0,利用這個作用,可以簡單實現判斷一個數是不是2^n和計算一個數的二進制序列中有幾個1;
  • 按位或,參與運算的兩個數各位相“或”,只要其中有一個二進制位值爲1,結果就爲1,如果要將一個數的某幾位置1,只需要與這幾位二進制序列是1的數進行或操作即可;
  • 按位異或,,參與運算的兩個數對應的二進制位相異或,當對應的兩個二進制位相異時,結果爲1,否則結果爲0,一個整數與0異或會保留原值;
  • 按位取反,在進行取反操作時不可簡單的認爲一個數取反後的結果就是該數的相反數;
  • 整數在內存中存放的是其二進制補碼,對其操作實際上是對二進制補碼的運算,所以左移和右移的操作數必須是整型數據;
  • 左移,其功能是把”<<”左邊的運算數的各二進制位全部左移若干位,由”<<”右邊的數指定其移動的位數,左移過程中高位丟棄,低位補0;在移出位不含1的情況下,左移一位相當於該數乘2;
  • 右移,右移運算符是雙目運算符,作用是把”>>”左邊的運算數的各二進制位全部右移若干位,由”<<”右邊的數指定其移動的位數;在進行右移時對於有符號數要注意符號位問題。當爲正數時,最高位補0;而爲負數時,最高位補0還是補1取決於編譯系統的決定,補0的稱爲“邏輯右移”,補1的稱爲“算術右移”,在我們計算時,一般採用邏輯右移,即高位補符號位,
  • 移位操作效率比乘除高,所以如果可以用左移/右移來代替乘2.除2時優先選擇左移/右移;
  • 無符號值執行的所有移位都是操作都是“邏輯移位”;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章