海明码(也叫汉明码)是一个可以有多个校验位,具有检测并纠正一位错误代码的纠错码。是计算机网络体系中很很重要的一个内容。
虽然学习不一定要为了考试,但是不得不说,在软考的相关教材中,海明码是写在前面的内容,可见是很基础的内容,但很多人第一次看都估计都一头雾水,我也是花了很大的功夫(可能是太笨吧),才看懂。
关于海明码的技术文章有很多,但是总感觉要么写的太专业了,要么就是太简洁了,要反复对比着看才能理解透彻,于是自己写了一篇来便于理解。以下内容主要参考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)来将其纠正。
要采用海明码纠错,需要按以下步骤来进行:
计算校验位数→确定校验码插入位置→确定校验码→实现校验和纠错。
下面来具体介绍这几个步骤。
设数据有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 |
之所以说是插入位置,是因为这些校验码不是直接附加在信息码的前面、后面或中间的,而是分开插入到不同的位置。
但不用担心,校验码的位置很容易确定的,那就是校验码必须是在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位置为校验位
知道校验码的插入位置后,接下来就是求出校验码的值了。
校验码的具体计算方法如下:
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。
虽然上一步已把各位校验码求出来了,但是如何实现检测出哪一位在传输过程中出了差错呢?(海明码也只能检测并纠正一位错误)它又是如何实现对错误的位进行纠正呢?其实最关键的原因就是海明码是一个多重校验码,也就是码字中的信息码位同时被多个校验码进行校验,然后通过这些码位对不同校验码的联动影响最终可以找出是哪一位出错了。
看起来有些复杂,还是回到这个表
从表中可以得出以下两个规律:
海明码校验的方式就是各校验码对它所校验的位组进行“异或运算”,即:
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两种情况。
海明码虽然看起来复杂,但是也只能检验一位,如果是多位出错,就不太适用了。