1. 程式人生 > >位運算之左移右移運算之詳解

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

先看如下一段左移右移的程式碼及其結果:

#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()
{
//leftshiftchar 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;
}

結果為:

127<<1=-2; 127<<2=-4;
127<<3=-8;
127<<4=-16;
127<<5=-32;
127<<6=-64;
127<<7=-128;
127<<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;

127>>1=63;
127>>2=31
;
127>>3=15;
127>>4=7;
127>>5=3;
127>>6=1;
127>>7=0;
127>>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、可通過某種演算法,使用異或實現交換兩個值 異或運算是有結合律的 取反(~)