from:
作為blog再次發出來,詳細描述一下crc32演算法的推導過程。
crc 演算法的數學基礎就不再多囉嗦了,到處都是,簡單提一下。它是以 gf(2) 多項式算術為數學基礎的,gf(2) 多項式中只有乙個變數 x ,其係數也只有 0 和 1 ,比如:
1 *x^6 + 0*x^5 + 1*x^4 + 0*x^3 + 0*x^2 +1*x^1 + 1*x^0
= x^6 + x^4 + x + 1
加減運算不考慮進製和退位。說白了就是下面的運算規則:
0 + 0 = 0 0 - 0 = 0
0 + 1 = 1 0 - 1 = 1
1 + 0 = 1 1 - 0 = 1
1 + 1 = 0 1 - 1 = 0
看看這個規則,其實就是乙個異或運算。
每個生成多項式的係數只能是 0 或 1 ,因此我們可以把它轉化為二進位制形式表示, 比如
g(x)=x^4 + x + 1
,那麼g(x)
對應的二進位制形式就是
10011
, 於是我們就把 gf(2) 多項式的除法轉換成了二進位制形式,和普通除法沒有區別,只是加減運算沒有進製和退位。
比如基於上述規則計算 11010/1001 ,那麼商是 11 ,餘數就是 101 ,簡單吧。
採用 crc 校驗時,傳送方和接收方用同乙個生成多項式 g(x) , g(x) 是乙個 gf(2) 多項式,並且 g(x) 的首位和最後一位的係數必須為 1 。
crc 的處理方法是:傳送方用傳送資料的二進位制多項式 t(x) 除以 g(x) ,得到餘數 y(x) 作為 crc 校驗碼。校驗時,以計算的校正結果是否為 0 為據,判斷資料幀是否出錯。設生成多項式是 r 階的(最高位是 x^r )具體步驟如下面的描述。
傳送方:
1 )在傳送的 m 位資料的二進位制多項式 t(x) 後新增 r 個 0 ,擴張到 m+ r 位,以容納 r 位的校驗碼,追加 0 後的二進位制多項式為 t(x) ;
2 )用 t(x) 除以生成多項式 g(x) ,得到 r 位的餘數 y(x) ,它就是 crc 校驗碼;
3 )把 y(x) 追加到 t(x) 後面,此時的資料 s(x) 就是包含了 crc 校驗碼的待傳送字串;由於 s(x) = t(x) y(x) ,因此 s(x) 肯定能被 g(x) 除盡。
接收方:
1 )接收資料 n(x) ,這個 n(x) 就是包含了 crc 校驗碼的 m+r 位資料;
2 )計算 n(x) 除以 g(x) ,如果餘數為 0 則表示傳輸過程沒有錯誤,否則表示有錯誤。從 n(x) 去掉尾部的 r 位資料,得到的就是原始資料。
生成多項式可不是隨意選擇的,數學上的東西就免了,以下是一些標準的 crc 演算法的生成多項式:
標準生成多項式
16 進製表示
crc12
x^12 + x^11 + x^3 + x^2 + x + 1
0x80f
crc16
x^16 + x^15 + x^2 + 1
0x8005
crc16-ccitt
x^16 + x^12 + x^5 + 1
0x1021
crc32
x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
0x04c11db7
根據多項式除法,我們就可以得到原始的 crc 校驗演算法。假設生成多項式 g(x)是r
階的,原始資料存放在
data
中,長度為
len個
bit,
reg是
r+1位的變數。 以 crc-4 為例,生成多項式 g(x)=x^4 + x + 1
,對應了乙個
5bits
的二進位制數字
10011
,那麼reg
就是 5 bits 。
reg[1]
表明reg
的最低位,
reg[r+1]
是reg
的最高位。
通過反覆的移位和進行除法,那麼最終該暫存器中的值去掉最高一位就是我們所要求的餘數。所以可以將上述步驟用下面的流程描述:
[cpp]view plain
copy
reg = 0;
data = data追加r個;
pos = 1;
while(pos <= len)
// 移出最高位,移入新資料
reg = (reg<<1) | (data[pos]);
pos++;
} return reg;
// reg中的後r位儲存的就是餘數
由於最後只需要
r位的餘數,所以我們可以嘗試構造乙個r位的
reg,初值為
0,資料
data
依次移入
reg[1]
,同時把
reg[r]
移出reg。
根據上面的演算法可以知道,只有當移出的資料為1時,
reg才和
g(x)
進行xor
運算;於是可以使用下面的演算法:
[cpp]view plain
copy
reg = 0;
data = data追加r個;
pos = 1;
while(pos
pos++;
} return reg;
// reg中儲存的就是餘數
這種演算法簡單,容易實現,對任意長度生成多項式的 g ( x )都適用,對應的 crc-32 的實現就是:
[cpp]view plain
copy
// 以4 byte資料為例
#define poly 0x04c11db7l // crc32生成多項式
unsigned int crc32_1(unsigned
int data)
return reg;
} 但是如果傳送的資料塊很長的話,這種方法就不太適合了。它一次只能處理乙個 bit 的資料,效率太低。考慮能不能每次處理乙個 byte 的資料呢?事實上這也是當前的 crc-32 實現採用的方法。
這一步驟是通往基於校驗表方法的橋梁,讓我們一步一步來分析上面逐 bit 的運算方式,我們把 reg 和 g(x) 都採用 bit 的方式表示如下:
考慮把上面逐 bit 的演算法執行 8 次,如果某次移出的不是 1 ,那麼 reg 不會和 g(x) 執行 xor 運算,事實上這相當於將 reg 和 0 執行了 xor 運算。執行過程如下所示,根據 hi-bit 的值,這裡的 g 可能是 g(x) 也可能是 0 。
從上面的執行過程清楚的看到,執行 8 次後, old-reg 的高 8bit 被完全移出, new-reg 就是 old-reg 的低24bit 和資料 data 新移入的 8bit 和 g 一次次執行 xor 運算所得到的。
xor 運算滿足結合律,那就是: a xor b xor c = a xor (b xor c) ,於是我們可以考慮把上面的運算分成兩步進行:
1 )先執行 r 高 8bit 與 g 之間的 xor 運算,將計算結果存入 x 中,如下面的過程所示。
2 )將 r 左移 8bit ,並移入 8bit 的資料,得到的值就是
根據 xor 運算的結合率,最後的結果就等於上面逐 bit 的演算法執行 8 次後的結果,根據這個分解,我們可以修改逐bit 的方式,寫出下面的演算法。
[cpp]view plain
copy
// 以4 byte資料為例
#define poly 0x04c11db7l // crc32生成多項式
unsigned int crc32_2(unsigned
int data)
// 計算步驟2
reg = (reg<<8)|p[i];
reg = reg ^ sum_poly;
} return reg;
}
CRC32演算法詳細推導(3)
看起來我們已經得到 crc 32 演算法的最終形式了,可是 可是在實際的應用中,資料傳輸時是低位先行的 對於乙個位元組 byte 來講,傳輸將是按照 b1,b2,b8 的順序。而我們上面的演算法是按照高位在前的約定,不管是 reg還是 g x g32,g31,g1 b8,b7,b1 r32,r31,...
CRC32演算法實現
crc32 檢錯能力極強,開銷小,易於用編碼器及檢測電路實現。從其檢錯能力來看,它所不能發現的錯誤的機率僅為0.0047 以下。從效能上和開銷上考慮,均遠遠優於奇偶校驗及算術和校驗等方式。因而,在資料儲存和資料通訊領域,crc無處不在 著名的通訊協議x.25的fcs 幀檢錯序列 採用的是crc cc...
深入了解crc32演算法
由於專案需要,解決乙個流 檔案的crc32校驗碼。網上查了很多的資料,發現了此校驗碼和生成多項式以及演算法本身都有關係。對於不同型別的檔案所使用的多項式以及演算法不同,對於不同的生成多項式所生成的crc32表不同,不同的演算法也會產生不同的結果。下面分模擬較兩種不同用途的crc32校驗碼的計算方法。...