位運算之左移右移運算之詳解

轉自:http://www.cnblogs.com/yyangblog/archive/2011/01/14/1935656.html


代碼
 
 #include "stdio.h"
 
 char leftshift(char i, int n)
 {
     if(n < 0)
         return -1;
     return i<<n;
 }
 
 char rightshift(char i, int n)
 {
     if(n < 0)
         return -1;
     return i>>n;
 }
 
 int main()
 {
     //leftshift
     char a1 = 127;
     char a2 = -1;
 
     for(int i = 1; i <= 8; i++)
         printf("%d<<%d = %d;\n", a1, i, leftshift(a1,i));
 
     for(i = 1; i <= 8; i++)
         printf("%d<<%d = %d;\n", a2, i, leftshift(a2,i));
 
     //rightshift
     a1 = 127;
     a2 = -128;
 
     for(i = 1; i <= 8; i++)
         printf("%d>>%d = %d;\n", a1, i, rightshift(a1,i));
 
     for(i = 1; i <= 8; i++)
         printf("%d>>%d = %d;\n", a2, i, rightshift(a2,i));
 
     return 0;
 }

結果
 <<1 = -2;
 <<2 = -4;
 <<3 = -8;
 <<4 = -16;
 <<5 = -32;
 <<6 = -64;
 <<7 = -128;
 <<8 = 0;
 
 -1<<1 = -2;
 -1<<2 = -4;
 -1<<3 = -8;
 -1<<4 = -16;
 -1<<5 = -32;
 -1<<6 = -64;
 -1<<7 = -128;
 -1<<8 = 0;
 >>1 = 63;
 >>2 = 31;
 >>3 = 15;
 >>4 = 7;
 >>5 = 3;
 >>6 = 1;
 >>7 = 0;
 >>8 = 0;
 
 -128>>1 = -64;
 -128>>2 = -32;
 -128>>3 = -16;
 -128>>4 = -8;
 -128>>5 = -4;
 -128>>6 = -2;
 -128>>7 = -1;
 -128>>8 = -1;

左移操作(<<)
 規則:
 右邊空出的位用0填補
 高位左移溢出則捨棄該高位。
 計算機中常用補碼錶示數據:
 數據 127,補碼和原碼一樣:0111 1111。
 左移一位: 1111 1110   -> 這個補碼對應的原碼爲:1000 0010  對應十進制:-2
 左移二位: 1111 1100   -> 這個補碼對應的原碼爲:1000 0100  對應十進制:-4
 左移三位: 1111 1000   -> 這個補碼對應的原碼爲:1000 1000  對應十進制:-8
 左移四位: 1111 0000   -> 這個補碼對應的原碼爲:1001 0000  對應十進制:-16
 左移五位: 1110 0000   -> 這個補碼對應的原碼爲:1010 0000  對應十進制:-32
 左移六位: 1100 0000   -> 這個補碼對應的原碼爲:1100 0000  對應十進制:-64
 左移七位: 1000 0000   -> 這個補碼對應的原碼爲:1000 0000  對應十進制:-128
 左移八位: 0000 0000   -> 這個補碼對應的原碼爲:0000 0000  對應十進制:0
 注:
 原碼到補碼的計算方式:取反+1,
 補碼到原碼的計算方式:-1再取反。
 數據-1,它的原碼爲1000 0001,補碼爲1111 1111
 左移一位: 1111 1110   -> 這個補碼對應的原碼爲:1000 0010  對應十進制:-2
 左移二位: 1111 1100   -> 這個補碼對應的原碼爲:1000 0100  對應十進制:-4
 左移三位: 1111 1000   -> 這個補碼對應的原碼爲:1000 1000  對應十進制:-8
 左移四位: 1111 0000   -> 這個補碼對應的原碼爲:1001 0000  對應十進制:-16
 左移五位: 1110 0000   -> 這個補碼對應的原碼爲:1010 0000  對應十進制:-32
 左移六位: 1100 0000   -> 這個補碼對應的原碼爲:1100 0000  對應十進制:-64
 左移七位: 1000 0000   -> 這個補碼對應的原碼爲:1000 0000  對應十進制:-128
 左移八位: 0000 0000   -> 這個補碼對應的原碼爲:0000 0000  對應十進制:0
 可以看出127和-1的結果完全一樣。移位操作與正負數無關,它只是忠實的將所有位進行移動,補0,捨棄操作。
 右移操作(>>)
 規則:
 左邊空出的位用0或者1填補。正數用0填補,負數用1填補。注:不同的環境填補方式可能不同;
 低位右移溢出則捨棄該位。
 1、127的補碼:0111 1111
 右移一位: 0011 1111   -> 原碼同補碼一樣  對應十進制:63
 右移二位: 0001 1111   -> 原碼同補碼一樣  對應十進制:31
 右移三位: 0000 1111   -> 原碼同補碼一樣  對應十進制:15
 右移四位: 0000 0111   -> 原碼同補碼一樣  對應十進制:7
 右移五位: 0000 0011   -> 原碼同補碼一樣  對應十進制:3
 右移六位: 0000 0001   -> 原碼同補碼一樣  對應十進制:1
 右移七位: 0000 0000   -> 原碼同補碼一樣  對應十進制:0
 右移八位: 0000 0000   -> 原碼同補碼一樣  對應十進制:0
 2、-128的補碼:1000 0000
 右移一位: 1100 0000   -> 這個補碼對應的原碼爲:1100 0000  對應十進制:-64
 右移二位: 1110 0000   -> 這個補碼對應的原碼爲:1010 0000  對應十進制:-32
 右移三位: 1111 0000   -> 這個補碼對應的原碼爲:1001 0000  對應十進制:-16
 右移四位: 1111 1000   -> 這個補碼對應的原碼爲:1000 1000  對應十進制:-8
 右移五位: 1111 1100   -> 這個補碼對應的原碼爲:1000 0100  對應十進制:-4
 右移六位: 1111 1110   -> 這個補碼對應的原碼爲:1000 0010  對應十進制:-2
 右移七位: 1111 1111   -> 這個補碼對應的原碼爲:1000 0001  對應十進制:-1
 右移八位: 1111 1111   -> 這個補碼對應的原碼爲:1000 0001  對應十進制:-1
 常見應用
 左移相當於*2,只是要注意邊界問題。如char a = 65; a<<1 按照*2來算爲130;但有符號char的取值範圍-128~127,已經越界,多超出了3個數值,所以從-128算起的第三個數值-126纔是a<<1的正確結果。
 而右移相當於除以2,只是要注意移位比較多的時候結果會趨近去一個非常小的數,如上面結果中的-1,0。
 其它的四種位運算:
 與運算(&)
 1、與0相與可清零
 2、與1相與可保留原值
 或運算(|)
 1、與0相或可保留原值
 2、與1相與可齊設1
 異或運算(^)
 1、與0異或保留原值
 2、與1異或比特值反轉
 3、可通過某種算法,使用異或實現交換兩個值
 異或運算是有結合律的
 取反(~)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章