奇偶校驗算法


1即計算出所給數中包含1的個數

方法一:每一位分別異或(時間復雜度O(n)n代表數位數)

函數功能:如果1的個數為奇數個,則返回1,如果1的個數為偶數個,則返回0。
parity_check(unsigned x)
{
int val=0;
while(x)
{
val^=x;//val 和x進行異或運算
x>>=1;//x右移一位
}
return val&0x1;//取末位運算. val的二進制形式最后一位位1則返回1,為0則返回0.
}
實例分析,假設無符號數x轉換成二進制后長度為5位,五個位置的數據(二進制數,0或者1)分別記為①②③④⑤,兩個位置的數進行異或運算記為①^②。注意,給定x后化成二進制形式最高位①為1。
則整個程序執行過程(只需要考慮異或運算結果的末位數)可以表述為:
(((⑤^④)^③)^②)^①——表達式1
假設⑤和④不同,則⑤^④運算結果為1,表示有一個1。表達式1可以化成:((1^③)^②)^①——表達式2
③如果不是1,則表示⑤④③中只有一個1;如果是1,⑤④③中有兩個1.這兩種結果等價於1^③運算的結果。假設③就是1,則表達式2可以化成:(0^②)^①——表達式3
假設②為0(①為1是前提),則表達式3可以化簡為:(0^0)^1,運算結果為1,即五個二進制數中有奇數個1,⑤和④中有一個1,③是1,②為0,①為1共3個1得以驗證。
該算法形式簡單,功能強大,卻不好理解。該函數可用於奇偶校驗。
 
上面方法有些問題:
如果輸入的X負數,負數右移,高位會被設為1,那么這個書最終就會變成oxFFFFFFFF而陷入死循環。
改進方法:
 
parity_check(unsigned x)
{
int val=0;
unsigned int flag=1;
while(flag)
{
val^=(x&flag)
flag=flag<<=1;//x左移一位 } return val&0x1;//取末位運算. val的二進制形式最后一位位1則返回1,為0則返回0. }

 

方法二:時間復雜度0(1的個數)
int a=1;
while(x)
{
a^=0;//改為 count++;可以計算該數二進制中包含1的個數
x&(x-1);
}
方法三:時間復雜度0(lgn)n為位數
8位的數據D(D7~D0),他的算法為:

D ^= D >>4;

D ^= D >>2;

D ^= D >>1;

D&=1;

最后D就是偶校驗的值了。

可能有的同學一時之間看不明白算法的原理,這里解釋一下吧。

首先從D里面找兩個位D1和D0,而D1D0的偶校驗值E0=D1^D0,這個大家都明白的,然后D3和D2的檢驗值E1=D3^D2,同理還有E2=D5^D4以及E3=D7^D6;

E0=1時代表了D1和D0里面有奇數個1,E1、E2和E3同理;

然后復習一下小學數學:奇數*奇數=奇數,偶數*奇數=偶數

如果E0和E1里面有奇數個1,那么D3~D0里面就有奇數數個1,此時D3~D0的偶校驗值為1;

“如果E0和E1里面有奇數個1”這句話的意思不就是求由E1和E0組成的兩位二進制的偶校驗么?而且當E1E0的偶校驗值F0=1時,對應的D3~D0的偶校驗值也為1。

同理,E3E2的偶校驗值F1=1時,對應的D7~D4的偶校驗值也為1;

繼續同理,由F1和F0組成的兩位二進制的偶校驗G0=1時,對應的是E3~E0的偶校驗值為1,同時對應的D7~D0的偶校驗值為1。

於是求D7~D0的偶校驗值變成了求F1F0的偶校驗值。

那么首先就要將D7~D0的8個位兩兩分組后在分別求異或,然后再將得出的值的4個位兩兩分組后分別異或,最后將得出的值的2個位進行異或,得到的值就是D7~D0的偶校驗值了。

而分組則不必是相鄰的,將D右移4位再和原來的D進行異或的話就簡單多了

D7——D3

D6——D2

D5——D1

D4——D0

如此類推,每次先進行右移,然后和原來的值異或,最終就能得到D的校驗值了;另外在計算的過程中,僅僅需要關注后面的位數就可以了,如第二次計算時,高4位會有一些數據,到最后高7位也會有數據的,但這些數據都已經沒有用了,所以最后只需要來一個&1就可以l。

於是文章開頭的那段8位二進制數的算法為:

D ^= D >>4;

D ^= D >>2;

D ^= D >>1;

D&=1;

另外對於2^N位二進制數,第一次右移(2^N)/2位后再異或,然后重復類似的計算N次就可以了。

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM