概述
有两种方式来确保计算机系统运行时信息传输的过程不出现错误,一个提升电路的可靠性,另一个则是寻求方法来 发现、纠正 错误,这就是校验码诞生的原因。
校验码的基本思想即把数据分为合法编码与非法编码,通过合理的设计编码规则,可以产生数据传输过程的任意错误都会使编码整体变为非法编码,这样一来就能发现传输过程中的错误。
一个指标叫做码距,指一个编码系统中,任意两个合法编码之间至少有多少个二进制位不同。如4位的BCD码的码距就为1。
常用的校验码有奇偶校验码、循环冗余校验码(CRC),此前已经在这篇文章详细说过:差错控制技术
下面主要详细讲一下海明码。
海明码(Hamming Code)
海明码是一种利用奇偶性来检错和纠错的校验法,因为它具备纠错能力所以也叫纠错码。
其构成方法是在数据中间的特定位置插入k个校验位,以此扩大码距实现检错纠错。
设数据位是n位,校验位k位,则n和k必须满足关系: 2 k − 1 ≥ n + k 2^k -1 \geq n+k 2k−1≥n+k。
编码规则
设k个校验位为 P k P k − 1 … P 1 P_k P_{k-1} \dots P_1 PkPk−1…P1,n个数据位为 D n − 1 D n − 2 … D 1 D 0 D_{n-1} D_{n-2} \dots D_1 D_0 Dn−1Dn−2…D1D0,之间对应的海明码为 H n + k H n + k − 1 … H 1 H_{n+k} H_{n+k-1} \dots H_1 Hn+kHn+k−1…H1,那么就有:
-
P i P_i Pi在海明码的第 2 i − 1 2^{i-1} 2i−1的位置,即 H j = P i H_j = P_i Hj=Pi,且 j = 2 i − 1 j = 2^{i-1} j=2i−1,数据位则按从低到高的顺序占据海明码中剩余的位置。
-
海明码中任一位都由若干个校验位校验,其关系如下:
被校验的海明位的下标等于所有参与校验该位的校验位下标之和,校验位由自身校验。
对于8位的数据,参照上面提到的关系,进行海明校验则需要4个校验位( 2 4 − 1 = 15 > 8 + 4 2^4 -1 = 15 > 8 + 4 24−1=15>8+4)。现在数据位为 D 7 D 6 … D 1 D 0 D_7 D_6 \dots D_1 D_0 D7D6…D1D0,校验位为 P 4 P 3 P 2 P 1 P_4 P_3 P_2 P_1 P4P3P2P1,形成的海明码为: H 12 H 11 … H 2 H 1 H_{12} H_{11} \dots H_2 H_1 H12H11…H2H1。
根据第1点的方式确定校验码P在海明码H中的位置为:
P 4 位 于 2 4 − 1 = H 8 P_4 位于 2^{4-1} = H_8 P4位于24−1=H8
P 3 位 于 2 3 − 1 = H 4 P_3位于2^{3-1} = H_4 P3位于23−1=H4
P 2 位 于 2 2 − 1 = H 2 P_2位于2^{2-1} = H_2 P2位于22−1=H2
P 1 位 于 2 1 − 1 = H 1 P_1位于2^{1-1} = H_1 P1位于21−1=H1
再将数据位按顺序占据海明码H剩余的位置,结果如下表:
H 12 H_{12} H12 H 11 H_{11} H11 H 10 H_{10} H10 H 9 H_9 H9 H 8 H_8 H8 H 7 H_7 H7 H 6 H_6 H6 H 5 H_5 H5 H 4 H_4 H4 H 3 H_3 H3 H 2 H_2 H2 H 1 H_1 H1 D 7 D_7 D7 D 6 D_6 D6 D 5 D_5 D5 D 4 D_4 D4 P 4 P_4 P4 D 3 D_3 D3 D 2 D_2 D2 D 1 D_1 D1 P 3 P_3 P3 D 0 D_0 D0 P 2 P_2 P2 P 1 P_1 P1 其校验关系如下所示:
海明码 下标 校验位组 H 1 ( P 1 ) H_1(P_1) H1(P1) 1 P 1 P_1 P1 H 2 ( P 2 ) H_2(P_2) H2(P2) 2 P 2 P_2 P2 H 3 ( D 0 ) H_3(D_0) H3(D0) 3 = 1+2 P 1 , P 2 P_1, P_2 P1,P2 H 4 ( P 3 ) H_4(P_3) H4(P3) 4 P 3 P_3 P3 H 5 ( D 1 ) H_5(D_1) H5(D1) 5 = 1+4 P 1 , P 3 P_1, P_3 P1,P3 H 6 ( D 2 ) H_6(D_2) H6(D2) 6 = 2+4 P 2 , P 3 P_2, P_3 P2,P3 H 7 ( D 3 ) H_7(D_3) H7(D3) 7 = 1+2+4 P 1 , P 2 , P 3 P_1, P_2, P_3 P1,P2,P3 H 8 ( P 4 ) H_8(P_4) H8(P4) 8 P 4 P_4 P4 H 9 ( D 4 ) H_9(D_4) H9(D4) 9 = 1+8 P 1 , P 4 P_1, P_4 P1,P4 H 10 ( D 5 ) H_{10}(D_5) H10(D5) 10 = 2+8 P 2 , P 4 P_2, P_4 P2,P4 H 11 ( D 6 ) H_{11}(D_6) H11(D6) 11 = 1+2+8 P 1 , P 2 , P 4 P_1, P_2, P_4 P1,P2,P4 H 12 ( D 7 ) H_{12}(D_7) H12(D7) 12 = 4+8 P 3 , P 4 P_3, P_4 P3,P4 一般的做法是采用偶校验,但若采用奇校验,则对校验位的偶校验值取反即可。
偶检验只需要使校验位等于其负责校验的所有位的异或就可以了。
-
检测错误
校验的过程非常简单,就是多个奇偶校验的和,如果全部都是正确的,那么数据就是正确的。但如果不全为正确的,就说明发现了错误。经过前面巧妙的编码,只需要将校验码按位组合起来,转换为十进制就可以得出错误的位置。因为二进制只有0和1,因此取反错误的位就能得出正确的结果。
但可以看出来,基础的海明码只能纠正一个位出现错误的情况。
例子
设仍然采用上面的8位数据位,4位校验位组合成海明码,现数据位D为10110110。
试求其海明码:
4位校验码的位置即 H 8 , H 4 , H 2 , H 1 H_8, H_4, H_2, H_1 H8,H4,H2,H1,设为偶校验,那么每个校验位P的值即:
P 1 = D 0 ⨁ D 1 ⨁ D 3 ⨁ D 4 ⨁ D 6 = 0 ⨁ 1 ⨁ 0 ⨁ 1 ⨁ 0 = 0 P_1 = D_0 \bigoplus D_1 \bigoplus D_3 \bigoplus D_4 \bigoplus D_6 = 0 \bigoplus 1 \bigoplus 0 \bigoplus 1 \bigoplus 0 = 0 P1=D0⨁D1⨁D3⨁D4⨁D6=0⨁1⨁0⨁1⨁0=0
P 2 = D 0 ⨁ D 2 ⨁ D 3 ⨁ D 5 ⨁ D 6 = 0 ⨁ 1 ⨁ 0 ⨁ 1 ⨁ 0 = 0 P_2 = D_0 \bigoplus D_2 \bigoplus D_3 \bigoplus D_5 \bigoplus D_6 = 0 \bigoplus 1 \bigoplus 0 \bigoplus 1 \bigoplus 0 = 0 P2=D0⨁D2⨁D3⨁D5⨁D6=0⨁1⨁0⨁1⨁0=0
P 3 = D 1 ⨁ D 2 ⨁ D 3 ⨁ D 7 = 1 ⨁ 1 ⨁ 0 ⨁ 1 = 1 P_3 = D_1 \bigoplus D_2 \bigoplus D_3 \bigoplus D_7 = 1 \bigoplus 1 \bigoplus 0 \bigoplus 1 = 1 P3=D1⨁D2⨁D3⨁D7=1⨁1⨁0⨁1=1
P 4 = D 4 ⨁ D 5 ⨁ D 6 ⨁ D 7 = 1 ⨁ 1 ⨁ 0 ⨁ 1 = 1 P_4 = D_4 \bigoplus D_5 \bigoplus D_6 \bigoplus D_7 = 1 \bigoplus 1 \bigoplus 0 \bigoplus 1 = 1 P4=D4⨁D5⨁D6⨁D7=1⨁1⨁0⨁1=1
因此得出的海明码为: ( 101110111000 ) 2 (101110111000)_2 (101110111000)2,每一位及其属性如下:
H 12 H_{12} H12 | H 11 H_{11} H11 | H 10 H_{10} H10 | H 9 H_9 H9 | H 8 H_8 H8 | H 7 H_7 H7 | H 6 H_6 H6 | H 5 H_5 H5 | H 4 H_4 H4 | H 3 H_3 H3 | H 2 H_2 H2 | H 1 H_1 H1 |
---|---|---|---|---|---|---|---|---|---|---|---|
D 7 D_7 D7 | D 6 D_6 D6 | D 5 D_5 D5 | D 4 D_4 D4 | P 4 P_4 P4 | D 3 D_3 D3 | D 2 D_2 D2 | D 1 D_1 D1 | P 3 P_3 P3 | D 0 D_0 D0 | P 2 P_2 P2 | P 1 P_1 P1 |
1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
假设数据传输中 D 4 D_4 D4即 H 9 H_9 H9出现了错误,接收方得到的海明码序列是:101 0 10111000。
将4个校验位校验一遍,就可以得出 P 1 , P 4 P_1, P_4 P1,P4的结果异常,校验序列P的结果为: ( 1001 ) 2 (1001)_2 (1001)2,转换成十进制是9,因此发现 H 9 H_9 H9发生错误,只需取反该位就可以得出正确结果。
一些细节
可以发现,海明码的校验位设置巧妙正式其不光具备奇偶校验这种发现错误的的能力,还能具体到某一位的错误。
原因相信也可以看出来一些端倪,海明码的校验位的数量之所以要满足条件,正是因为需要满足能发现错误到某一位的能力。
如果将每个校验位负责校验的位置标注出来,就能得出下表:
这里更深刻的能得出三个规律:
-
海明码校验位负责校验的数据分布就如同二进制一般,多个校验位的不同结果能组合出唯一任意的一位。
-
第x位的校验由校验位的海明码下标组成,且总是唯一的。
如 H 14 H_{14} H14的校验位组是由在 H 8 H_8 H8的 P 4 P_4 P4 、在 H 4 H_4 H4的 P 3 P_3 P3、在 H 2 H_2 H2的 P 2 P_2 P2共同组成(14 = 8 + 4 + 2)。
-
前面提到海明码校验位 P i P_i Pi 所在位置是 H 2 i − 1 H_{2^{i-1}} H2i−1,并且其总是从第 i i i个校验位起,校验 2 i − 1 2^{i-1} 2i−1位,跳过 2 i − 1 2^{i-1} 2i−1位,总是如此。如:
校验位 P 1 P_1 P1从它自身起,每校验 2 1 − 1 = 2 0 = 1 2^{1-1} = 2^0 = 1 21−1=20=1位,跳过1位。
校验位 P 2 P_2 P2从它自身起,每校验 2 2 − 1 = 2 1 = 2 2^{2-1} = 2^1 = 2 22−1=21=2位,跳过2位。
校验位 P 3 P_3 P3从它自身起,每校验 2 3 − 1 = 2 2 = 4 2^{3-1} = 2^2 = 4 23−1=22=4位,跳过4位。
校验位 P 4 P_4 P4从它自身起,每校验 2 4 − 1 = 2 3 = 8 2^{4-1} = 2^3 = 8 24−1=23=8位,跳过8位。
上表只表现到了 P 5 P_5 P5,但以此类推我们可以推断 P 6 P_6 P6的起始位置和负责校验的海明码位:
P 6 P_6 P6的起始位置为 H 2 6 − 1 = H 32 H_{2^{6-1}} = H_{32} H26−1=H32,并且从它自身起每校验32位,跳过32位。