位運算符及其應用

一、C語言的六種位運算符:

按位與

按位或

按位異或

取反

<< 左移

>> 右移

1.   按位與運算

按位與運算符"&"是雙目運算符。

        其功能是參與運算的兩數各對應的二進位相與。只有對應的兩個二進位均為1時,結果位才為1 ,否則為0。參與運算的數以補碼方式出現。

例如:9&5可寫算式如下: 00001001 (9的二進制補碼)&00000101 (5的二進制補碼) 00000001 (1的二進制補碼)可見9&5=1。

         按位與運算通常用來對某些位清0或保留某些位。例如把a 的高八位清 0 , 保留低八位, 可作 a&255 運算 ( 255 的二進制數為0000000011111111)。

main(){  
    int a=9,b=5,c;  
    c=a&b;  
    printf("a=%d\nb=%d\nc=%d\n",a,b,c);  
}

2.按位或運算

按位或運算符“|”是雙目運算符。

         其功能是參與運算的兩數各對應的二進位相或。只要對應的二個二進位有一個為1時,結果位就為1。參與運算的兩個數均以補碼出現。

例如:9|5可寫算式如下: 00001001|00000101

00001101 (十進制為13)可見9|5=13

main(){  
    int a=9,b=5,c;  
    c=a|b;  
    printf("a=%d\nb=%d\nc=%d\n",a,b,c);

3.按位異或運算

按位異或運算符“^”是雙目運算符。

        其功能是參與運算的兩數各對應的二進位相異或,當兩對應的二進位相異時,結果為1。參與運算數仍以補碼出現。

        例如9^5可寫成算式如下: 00001001^00000101 00001100 (十進制為12)

main(){  
    int a=9;      
    a=a^15;  
    printf("a=%d\n",a);  
}

4. 求反運算

求反運算符~為單目運算符,具有右結合性。 

       其功能是對參與運算的數的各二進位按位求反。

例如~9的運算為: ~(0000000000001001)結果為:1111111111110110

5. 左移運算

左移運算符“<<”是雙目運算符。左移n位就是乘以2的n次方。

        其功能把“<<”左邊的運算數的各二進位全部左移若干位,由“<<”右邊的數指定移動的位數,高位丟棄,低位補0。

        1)例: a<<4 指把a的各二進位向左移動4位。如a=00000011(十進制3),左移4位后為00110000(十進制48)。

        2)例:

         int i = 1;

         i = i << 2;  //把i里的值左移2位

         也就是說,1的2進制是000…0001(這里1前面0的個數和int的位數有關,32位機器,gcc里有31個0),左移2位之后變成 000…0100,也就是10進制的4,所以說左移1位相當于乘以2,那么左移n位就是乘以2的n次方了(有符號數不完全適用,因為左移有可能導致符號變化,下面解釋原因)

        需要注意的一個問題是:int類型最左端的符號位和移位移出去的情況.  我們知道,int是有符號的整形數,最左端的1位是符號位,即0正1負,那么移位的時候就會出現溢出,

       例如:

        int i = 0x40000000; //16進制的40000000,為2進制的01000000…0000

        i = i << 1;

      那么,i在左移1位之后就會變成0x80000000,也就是2進制的100000…0000,符號位被置1,其他位全是0,變成了int類型所能表示的最小值,32位的int這個值是-2147483648,溢出.如果再接著把i左移1位會出現什么情況呢?在C語言中采用了丟棄最高位的處理方法,丟棄了1之后,i的值變成了0.

        左移里一個比較特殊的情況是當左移的位數超過該數值類型的最大位數時,編譯器會用左移的位數去模類型的最大位數,然后按余數進行移位,如:

        int i = 1, j = 0x80000000; //設int為32位

        i = i << 33;   // 33 % 32 = 1 左移1位,i變成2

        j = j << 33;   // 33 % 32 = 1 左移1位,j變成0,最高位被丟棄

        在用gcc編譯這段程序的時候編譯器會給出一個warning,說左移位數>=類型長度.那么實際上i,j移動的就是1位,也就是33%32后的余數.在gcc下是這個規則,別的編譯器是不是都一樣現在還不清楚.

總之左移就是: 丟棄最高位,0補最低位

6. 右移運算

右移運算符“>>”是雙目運算符。右移n位就是除以2的n次方

其功能是把“>>”左邊的運算數的各二進位全部右移若干位,“>>”右邊的數指定移動的位數。

例如:設 a=15,a>>2 表示把000001111右移為00000011(十進制3)。 

應該說明的是,對于有符號數,在右移時,符號位將隨同移動。當為正數時, 最高位補0,而為負數時,符號位為1,最高位是補0或是補1 取決于編譯系統的規定。Turbo C和很多系統規定為補1。

右移對符號位的處理和左移不同:

對于有符號整數來說,比如int類型,右移會保持符號位不變,例如:

int i = 0x80000000;

i = i >> 1;  //i的值不會變成0x40000000,而會變成0xc0000000

就是說,對于有符號數, 符號位向右移動后,正數的話補0,負數補1,

對于有符號數,在右移時,符號位將隨同移動:

當為正數時, 最高位補0,

而為負數時,符號位為1,

也就是匯編語言中的算術右移.同樣當移動的位數超過類型的長度時,會取余數,然后移動余數個位.

最高位是補0或是補1 取決于編譯系統的規定。Turbo C和很多系統規定為補1。

負數10100110 >>5(假設字長為8位),則得到的是  11111101

總之,在C中,左移是邏輯/算術左移(兩者完全相同),右移是算術右移,會保持符號位不變.實際應用中可以根據情況用左/右移做快速的乘/除運算,這樣會比循環效率高很多. x>>1;   //相當于 x /= 2x<<1;   //相當于 x *= 2x>>2;   // x /=4x<<2;   // x *= 4x>>3;   // x /= 8x<<3;   // x *= 8以此類推.

無符號:

main(){  
    unsigned a,b;  
    printf("input a number: ");  
    scanf("%d",&a);  
    b=a>>5;  
    b=b&15;  
    printf("a=%d\tb=%d\n",a,b);  
  
}

請再看一例!

main(){  
    char a='a',b='b';  
    int p,c,d;  
    p=a;  
    p=(p<<8)|b;  
    d=p&0xff;  
    c=(p&0xff00)>>8;  
    printf("a=%d\nb=%d\nc=%d\nd=%d\n",a,b,c,d);  
}

二、異或操作的妙用 

1. 使特定位翻轉     要使哪幾位翻轉就將與其進行∧運算的該幾位置為1即可。

2 與0相∧,保留原值.

3.交換兩個值,不用臨時變量.

我們可以在不用引入其他變量就可以實現變量值的交換

用異或操作可以實現:

      a = a^b;          //(1)
      b = a^b;          //(2)
      a = a^b;          //(3)

異或操作滿足結合律和交換律,且由異或操作的性質知道,對于任意一個整數a^a=0;

證:(第(2)步中的a) a = a^b =(將第(1)步中的b代入b) a^(a^b) = b;

(第(3)步中的b)b =a^b = (將第(1)步中的b代入b,將第(2)步中的a代入a) a^b^a^a^b = a^a^a^b^b = a;

 

三 、位與運算

1 . 清零      A數中為1的位,B中相應位為0。然后使二者進行&運算,即可達到對A清零目的。

2 . 取一個數中某些指定位 取數A的某些位,把數B的某些位置1,就把數A的某些位與1按位與即可。

3 . 保留一位的方法     數A與數B進行&運算,數B在數A要保留的位1,其余位為零。

4 .  判斷奇偶性 將變量 a的奇偶性。a與1做位與運算,若結果是1,則 a是奇數;將 a與1做位與運算,若結果是0,則 a是偶數。

4、應用舉例

1 .判斷int型變量a是奇數還是偶數           

a&1   = 0 偶數
a&1 =   1 奇數

2 . 取int型變量a的第k位

(k=0,1,2……sizeof(int)),即a>>k&1

3 . 將int型變量a的第k位清0,即a=a&~(1<<k)

4 . 將int型變量a的第k位置1, 即a=a|(1<<k)

5 . int型變量循環左移k次,即a=a<<k|a>>16-k   (設sizeof(int)=16)

6 . int型變量a循環右移k次,即a=a>>k|a<<16-k   (設sizeof(int)=16)

7. 整數的平均值

對于兩個整數x,y,如果用 (x+y)/2 求平均值,會產生溢出,因為 x+y 可能會大于INT_MAX,但是我們知道它們的平均值是肯定不會緋齙?,晤U怯萌縵濾惴ǎ?/DIV>

int average(int x, int y)   //返回X,Y 的平均值
{   
     return (x&y)+((x^y)>>1);
}

8 . 判斷一個整數是不是2的冪,對于一個數 x >= 0,判斷他是不是2的冪

boolean power2(int x)
{
    return ((x&(x-1))==0)&&(x!=0);
}

9 不用temp交換兩個整數
void swap(int x , int y)
{
    x ^= y;
    y ^= x;
    x ^= y;
}

php:
$a ='dd';
$b = 'bb';

$a = $a ^ $b;
$b = $a ^ $b;
$a = $a ^ $b;
echo $a,' ', $b;

10 計算絕對值
int abs( int x )
{
    int y ;
    y = x >> 31 ;
     return (x^y)-y ;        //or: (x+y)^y
}

11. 取模運算轉化成位運算 (在不產生溢出的情況下)
         a % (2^n) 等價于 a & (2^n – 1)

12 乘法運算轉化成位運算 (在不產生溢出的情況下)
         a * (2^n) 等價于 a<< n

13. 除法運算轉化成位運算 (在不產生溢出的情況下)
         a / (2^n) 等價于 a>> n
        例: 12/8 == 12>>3

14 . a % 2 等價于 a & 1  ( a  & log2(2))      
       a % 4 等價于 a & 2  ( a  & log2(4))  

      …..       
       a % 32 等價于 a & 5


15 if (x == a) x= b;
    else x= a;
 等價于 x= a ^ b ^ x;

16 x 的 相反數 表示為 (~x+1)

轉自:http://blog.csdn.net/hguisu/article/details/7892596

原創文章,作者:s19930811,如若轉載,請注明出處:http://www.www58058.com/2747

(1)
s19930811s19930811
上一篇 2015-11-18
下一篇 2015-11-18

相關推薦

欧美性久久久久