1. 程式人生 > >C語言位操作--奇偶校驗演算法

C語言位操作--奇偶校驗演算法

     資訊是以位元流的方式傳輸的,類似01000001。在傳輸過程中,有可能會發生錯誤,比如,我們儲存了01000001,但是取出來卻是01000000,即低位由0變成了1。為了檢測到這種錯誤,我們可以通過“奇偶校驗”來實現。假如,我們儲存的資料是一個位元組,8個位元位,那我們就可以計算每個位元組位元位是1的個數,如果是偶數個1,那麼,我們就把第九個位設為1,如果是奇數個1,那麼就把第九個位設為0,這樣連續9個位元組位元位為1的位數肯定是奇數。這中方法叫做“奇校驗”,“偶校驗”和此類似。當然,在實際應用中,也可以把一個位元組的前7位作為資料位,最後一個為作為校驗位。

1、奇偶校驗的常規方法:

unsigned int v;       // 待檢測的數字
bool parity = false;  //初始判斷標記
while (v)
{
  parity = !parity;
  v = v & (v - 1);
}


通過while迴圈,每執行一次,v中1的數目就會減少1,如果v中1的數目為奇數,則parity=true,否則parity=false。

2、通過構建字典表進行奇偶校驗:

static const bool ParityTable256[256] = 
{
#   define P2(n) n, n^1, n^1, n
#   define P4(n) P2(n), P2(n^1), P2(n^1), P2(n)
#   define P6(n) P4(n), P4(n^1), P4(n^1), P4(n)
    P6(0), P6(1), P6(1), P6(0)
};

通過巢狀巨集定義,製作一張包括0~255各個數字中包含1的個數,其中包含偶數個1,則ParityTable256[i]=0,否則ParityTable256[i]=1;

如果要判定char型別的b中i的個數的奇偶,可以直接使用下面的程式碼:

unsigned char b;  
bool parity = ParityTable256[b];

而對於32-bit的數,則使用下面的程式碼:

unsigned int v;
v ^= v >> 16;
v ^= v >> 8;
bool parity = ParityTable256[v & 0xff];

原理:

(1)通過v^=v>>16,將v中的低16位與高16位進行按位或(^)操作, 相當於0~16位保留1的總個數的奇偶與v中的1的總 個數的奇偶相同;

(2)通過v^=v>>8,將v中的9~16位與0~8位進行按位或(^)操作,相當於0~8位保留1的總個數的奇偶與0~16中1的總個數的奇偶相同;

(3)通過(1)(2)操作,最初v中1的總個數的奇偶與最後v中1~8位中1的總個數的奇偶相同,v&0xff相當於獲取v中1~8位元位的1,然後再查表即可。

或者使用如下的程式碼:

unsigned char * p = (unsigned char *) &v;
parity = ParityTable256[p[0] ^ p[1] ^ p[2] ^ p[3]];

原理:取v的地址,並進行強制型別轉換為char*,

e.g. v=1234

二進位制表示為:

00000000 00000000 00000100 11010010

p[0]:11010010

p[1]:00000100

p[2]:00000000

p[3]:00000000

    ^------------

       11010110

 通過p[0] ^ p[1] ^ p[2] ^ p[3]] 操作,將p[i]中的所有的1都放在一個8位的數中,然後查表即可

3、使用64位乘法與模除法進行奇偶校驗

unsigned char b;
bool parity = 
  (((b * 0x0101010101010101

原理:
0x0101010101010101ULL://00000001 0000 0001 0000 0001 0000 0001 0000 0001 0000 0001 0000 0001 0000 0001

0x8040201008040201ULL://1000 0000 0100 0000 0010 0000 0001 0000 0000 1000 0000 0100 0000 0010 0000 0001

0x1FF:  //0001 1111 1111

 b * 0x0101010101010101ULL  將1~8位設定為b的二進位制位元位,