头图

计算机使用的是2进制(0和1)存储和传输数据。但是这样做会有1定的几率(非常非常小)出现错误,导致0变成了1或者1变成了0。那么,计算机是怎么知道自己出现了错误呢?

三重码

三重码,顾名思义,就是把重要的事情说三遍。如果有数据损坏,那么可以通过其他的数据来修复损坏的数据。如果只有1个以下的地方出错,就可以修复:

原始数据00001111
发送数据000000000000111111111111
接收数据000001010100111110101011
还原数据00001111

那么有2个以上地方出错,那么就不能修复了(虽然概率非常低):

原始数据00001111
发送数据000000000000111111111111
接收数据011101110111100010001000
还原数据11110000

但是,出错的概率是很低的,使用三重码会传输三次原始数据,导致效率下降。既然如此,纠错的频率可以降低1些。

奇偶校验码

奇偶校验码的工作原理是统计1段2进制数中数字“1”出现的次数。如果这1段中出现偶数个“1”,那么校验码是“0”;如果出现奇数个“1”,那么校验码是“1”。下面是1个8位的简单的例子:

原始数据接收数据校验码
0100 10100100 10101
0100 10100100 10001

在原始数据“0100 1010”中,数字“1”出现了3次(奇数次),所以校验码是“1”。但是在第2个数据中,接收的数据“0100 1000”中数字“1”只出现了2次(偶数次),校验码本该是“0”,但是接收的校验码是“1”,所以判断这个数据有误。

但是奇偶校验码只能判断1个以内的错误。因为奇偶校验码只能告诉数字“1”出现的次数的奇偶性,所以出现2个错误,奇偶校验码就没用了。

根据奇偶校验码的特性,可以想到用行列定位错误的位置。下面是1个16位的例子:

实际数据 校验码
01001
10100
01001
10001
校验码0010
错误数据 校验码
01001
10000
01001
10001
校验码0010

由此,可以很快确定出错的位置。但是出错2个连续的地方就没办法定位了:

错误数据 校验码
01001
10010
01001
10001
校验码0010

因为每1行的校验码都是正确的,所以无法定位。而且这样的效率还是太低了,16位数据需要8个校验码。于是查德·卫斯里·汉明发明了——汉明码。

汉明码

有1道著名的智力谜题:16杯水中有1杯有毒,如何用最少的化验次数判断哪杯有毒?

解题思路:随机选取8杯化验,如果有毒,那么有毒的杯子就在这8杯里;如果没毒,那么有毒的杯子就在另外8杯里面。再选取4杯化验……如此化验4次,直到确定1杯有毒的。这样概括解题思路:错误如果不在这1半,那么1定在那1半。我们继续使用16位的例子:

原始数据校验码
0100 1010 0100 10000
0100 1010 0100 10001
0100 1010 0100 10001
0100 1010 0100 10000

由此计算出“0100 1010 0100 1000”的4位校验码是“0110”。

如果接收数据是“0100 1000 0100 1000”,那么这样的校验码是“0000”,与接收到的校验码“0110”不符,所以接收数据有误。

第1个和第4个的校验码无误,所以错误不在这些地方:

0100 1000 0100 1000

第2个和第3个的校验码有误,所以错误同时在第2个和第3个校验的地方:

0100 1000 0100 1000

根据上面的分析结果,错误只能在:

0100 1000 0100 1000

所以正确的数据应该是:

0100 1010 0100 1000

但是……这个操作有个问题:发生在第1位的错误是检测不出来的。也就是说4位校验码可以校验15位数。而且又迎来了1个问题:数据没错,校验码有误,那么怎么办呢?汉明的方法是将校验码和原始数据混合在1起:在11位中混入4位校验。

位置位置的2进制值备注
10001 留空
20010 留空
300110
40100 留空
501011
601100
701110
81000 留空
910011
1010100
1110111
1211000
1311010
1411101
1511110

会发现:留空的位置的2进制值中只有1位是“1”。

计算校验码时,先计算位置的2进制值第1位是“1”的奇偶校验码,比如位置“1001”、“1010”,填入第8位;再计算位置的2进制值第2位是“1”的奇偶校验码,比如位置“0101”、“1110”,填入第4位;然后计算位置的2进制值第3位是“1”的奇偶校验码,比如位置“0110”、“1010”,填入第2位;最后计算位置的2进制值第4位是“1”的奇偶校验码,比如位置“1001”、“1011”,填入第1位。

那么,我们会得到:

位置位置的2进制值备注
100011留空
200100留空
300110
401000留空
501011
601100
701110
810001留空
910011
1010100
1110111
1211000
1311010
1411101
1511110

如果第5位出现错误,那么第1位和第4位校验码会出错。由排列方式可知:如果数据出错,那么1定会导致2个或者以上校验码出错,因为数据位置的2进制值不仅仅有1个“1”。如果只有1个校验码出错,那么只能说明是校验码本身的问题。如上的方式可以纠正1位错误。那么出现2位错误呢?我们可以设置第0位数来表示后面15位数的奇偶校验码:

0100 0100 1101 0010

当后面的数据出现1位错误时,第0位能察觉出错误;当后面的数据出现2位错误时,第0位察觉不出错误,但是校验码可以察觉错误;这样,汉明码就具备了纠正1位错误,察觉2位错误的能力。当出现2位错误时,虽然不能纠正,但是可以让对方再发送一遍消息来纠正错误。

那么……出现三个错误呢?汉明码就察觉不了了,就需要类似里德-所罗门纠错码的其他纠错码了。


水蒸气
178 声望46 粉丝

以我渺小的灵魂,为无穷的 (BUG) 生活写下这诗篇。