簡介
海明碼(也叫漢明碼)是一個可以有多個校驗位,具有檢測並糾正一位錯誤代碼的糾錯碼。是計算機網絡體系中很很重要的一個內容。
雖然學習不一定要為了考試,但是不得不說,在軟考的相關教材中,海明碼是寫在前面的內容,可見是很基礎的內容,但很多人第一次看都估計都一頭霧水,我也是花了很大的功夫(可能是太笨吧),才看懂。
關於海明碼的技術文章有很多,但是總感覺要么寫的太專業了,要么就是太簡潔了,要反復對比着看才能理解透徹,於是自己寫了一篇來便於理解。以下內容主要參考csdn和51cto兩位大神的內容,自己加了一些整理。
https://blog.csdn.net/flyyufenfei/article/details/72235748
王達博客:(一)https://blog.51cto.com/winda/1068000
(二)https://blog.51cto.com/winda/1072629
海明碼的檢錯、糾錯基本思想是將有效信息按某種規律分成若干組,每組安排一個校驗位進行奇偶性測試,然后產生多位檢測信息,並從中得出具體的出錯位置,最后通過對錯誤位取反(也是原來是1就變成0,原來是0就變成1)來將其糾正。
要采用海明碼糾錯,需要按以下步驟來進行:
計算校驗位數→確定校驗碼插入位置→確定校驗碼→實現校驗和糾錯。
下面來具體介紹這幾個步驟。
1、計算校驗位數
設數據有n位,校驗碼有x位。則校驗碼一共有2x種取值方式。其中需要一種取值方式表示數據正確,剩下2x-1種取值方式表示有一位數據出錯。因為編碼后的二進制串有n+x位,因此x應該滿足
2x-1 ≥ n+x
得到數據的位數后,解這個不等式的x的最小解就是校驗碼的位數。
此不等式包含指數函數,但是由於x是正整數,所以一般只要挨個試就可以了,個人計算不會出現太多的位數,以下為數據位數和校驗碼位數的關系:
數據位數 | 1 | 2~4 | 5~11 | 12~26 | 27~57 | 58~120 | 121~247 |
檢驗碼位數 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
3、確定校驗碼插入位置
之所以說是插入位置,是因為這些校驗碼不是直接附加在信息碼的前面、后面或中間的,而是分開插入到不同的位置。
但不用擔心,校驗碼的位置很容易確定的,那就是校驗碼必須是在2n次方位置,如第1、2、4、8、16、32,……位(對應20、21、22、23、24、25,……,是從最左邊的位數起的)。
剩下的非2n的位置就是數據位。
例如下面這個例子,p表示校驗位,b表示數據位
位置 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
內容 | p1 | p2 | b1 | p3 | b2 | b3 | b4 | p4 | b5 | b6 | b7 |
1、2、4、8位置為校驗位
3、確定校驗碼
知道校驗碼的插入位置后,接下來就是求出校驗碼的值了。
校驗碼的具體計算方法如下:
p1(第1個校驗位,也是整個碼字的第1位)的校驗規則是:從當前位數起,校驗1位,然后跳過1位,再校驗1位,再跳過1位,……。
這樣就可得出p1校驗碼位可以校驗的碼字位包括:第1位(也就是p1本身)、第3位、第5位、第7位、第9位、第11位、第13位、第15位,……。然后根據所采用的是奇校驗,還是偶校驗,最終可以確定該校驗位的值。
p2(第2個校驗位,也是整個碼字的第2位)的校驗規則是:從當前位數起,連續校驗2位,然后跳過2位,再連續校驗2位,再跳過2位,……。
這樣就可得出p2校驗碼位可以校驗的碼字位包括:第2位(也就是p2本身)、第3位,第6位、第7位,第10位、第11位,第14位、第15位,……。同樣根據所采用的是奇校驗,還是偶校驗,最終可以確定該校驗位的值。
p3(第3個校驗位,也是整個碼字的第4位)的校驗規則是:從當前位數起,連續校驗4位,然后跳過4位,再連續校驗4位,再跳過4位,……。
這樣就可得出p4校驗碼位可以校驗的碼字位包括:第4位(也就是p4本身)、第5位、第6位、第7位,第12位、第13位、第14位、第15位,第20位、第21位、第22位、第23位,……。同樣根據所采用的是奇校驗,還是偶校驗,最終可以確定該校驗位的值。
p4(第4個校驗位,也是整個碼字的第8位)的校驗規則是:從當前位數起,連續校驗8位,然后跳過8位,再連續校驗8位,再跳過8位,……。
這樣就可得出p4校驗碼位可以校驗的碼字位包括:第8位(也就是p4本身)、第9位、第10位、第11位、第12位、第13位、第14位、第15位,第24位、第25位、第26位、第27位、第28位、第29位、第30位、第31位,……。同樣根據所采用的是奇校驗,還是偶校驗,最終可以確定該校驗位的值。
……
結合這張圖能更清晰
然后把每一組,也就是圖中的每一行,進行異或運算,對應表示為G1、G2、G3、G4,……,正常情況下均為0。就可以求得p1,p2,p3,p4的值。
這樣的說法是比較好理解與記憶的。計算采用二進制會比較方便,以求p2的值為例。為了直觀,將表格中的位置用二進制表示。並假設數據如下:
位數 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 |
內容 | p1 | p2 | 1 | p3 | 0 | 1 | 0 | p4 | 1 | 1 | 0 |
為了求出p2,要使所有位置的第二位是1的數據(即形如**1*的位置的數據)的異或值為0。即p2^1^1^0^1^0 = 0。因此x2 = 1。
同理可得x1 = 0, x3 = 1, x4 = 0。
位數 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 |
內容 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 |
因此1010110的海明碼為01110100110。
4、檢驗和糾錯
雖然上一步已把各位校驗碼求出來了,但是如何實現檢測出哪一位在傳輸過程中出了差錯呢?(海明碼也只能檢測並糾正一位錯誤)它又是如何實現對錯誤的位進行糾正呢?其實最關鍵的原因就是海明碼是一個多重校驗碼,也就是碼字中的信息碼位同時被多個校驗碼進行校驗,然后通過這些碼位對不同校驗碼的聯動影響最終可以找出是哪一位出錯了。
看起來有些復雜,還是回到這個表
從表中可以得出以下兩個規律:
- 所有校驗碼所在的位是只由對應的校驗碼進行校驗,如第1位(只由p1校驗)、第2位(只由p2校驗)、第4位(只由p3校驗)、第8位(只由p4校驗)、第16位(只由p5校驗),……。也就是這些位如果發生了差錯,影響的只是對應的校驗碼的校驗結果,不會影響其它校驗碼的校驗結果。這點很重要,如果最終發現只是一個校驗組中的校驗結果不符,則直接可以知道是對應校驗組中的校驗碼在傳輸過程中出現了差錯。
- 所有信息碼位均被至少兩個校驗碼進行了校驗,也就是至少校驗了兩次。查看對應的是哪兩組校驗結果不符,然后根據表5-2就可以很快確定是哪位信息碼在傳輸過程中出了差錯。
海明碼校驗的方式就是各校驗碼對它所校驗的位組進行“異或運算”,即:
G1=p1⊕b1⊕b2⊕b4⊕b5⊕……
G2=p2⊕b1⊕b3⊕b4⊕b6⊕b7⊕b10⊕b11⊕……
G3= p3⊕b2⊕b3⊕b4⊕b8⊕b9⊕b10⊕b11⊕……
G4= p4⊕b5⊕b6⊕b7⊕b8⊕b9⊕b10⊕b11⊕……
正常情況下,也就是沒有差錯的時候,結果應該都為0。如果出了差錯,對應組就會變成1,運算中包含出錯位的組肯定不止一組,找到這些組中的公共部分,(不包含校驗位),就可以知道出錯的是哪一位。
位數 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 |
內容 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 |
舉個栗子:
加入上述數據的第11位除了錯誤,也就是b7
那么得到的結果是,G3=0。G1,G2,G4都等於1。可以發現,除去校驗位1、2、4、8位,G1G2G4中都包括第十一位b7,所以出錯的在第11位。
把位數用二進制表示
將所有位置形如***1, **1*, *1**, 1***的數據分別異或。
***1: 0^1^0^0^1^1 = 1
**1*: 1^1^1^0^1^1 = 1
*1**: 1^0^1^0 = 0
1***: 0^1^1^1 = 1
以上四組中,如果一組異或值為1,說明該組中有數據出錯了。***1 **1* 1***的異或都為1,說明出錯數據的位置為1011,也是11位。
糾錯過程則只要把對應出錯的位置取反就可以了,無非是0和1兩種情況。
海明碼雖然看起來復雜,但是也只能檢驗一位,如果是多位出錯,就不太適用了。