Hamming码是什么?如何计算和使用?

第一次知道 Hamming 码是几年前看到 3Blue1Brown 的【官方双语】汉明码Pa■t1,如何克服噪■ - BiliBili,然后了解了一下 Hamming 这个人,只是觉得这人是厉害的。后来印象深刻是在《UNIX 传奇》中发现,Hamming 居然是 Brian(就是写 C 语言圣经 K&R 的那个人)在贝尔实验室的导师,第三届图灵奖得主,有一种历史传承的感觉,然后就去看了他的图灵奖演讲稿,说实话 Hamming 的很多观点非常有意思,从 Brian 的描述中也可以看出是一个很幽默的人,感兴趣可以自己看看。

我看数学科普视频永远记不住,可能是电波对不上,所以还是自己研究了一下。

汉明码是什么

在原始论文中,Hamming 阐述了一种检查和纠错编码:系统性代码(Systematic Code)。

系统性代码的结构是:假设二进制位数为n,其中m位用于表示数据,k位用来检错和纠错。这就产生了一个冗余率R=n/m,使用这个冗余率R来作为传递相同信息的最小必要数。

当时可能是信道容量真的不足,Hamming 在文章开头多次强调检查和纠正错误会降低信道的利用率。

论文中构建了三种最小冗余的码:

  • 单个错误检测码(奇偶校验码);
  • 单个错误纠正码;
  • 单个错误纠正和双错误检测码。

后两个都称为汉明码(Hamming Code),因为都是 Hamming 发明的,所以也有叫汉明码族的。不过单个错误纠正码是用的思路是最关键的。

单个错误检测码(奇偶校验码)

这个就是利用最高位来检测是否发生错误,如果所有位为偶数,则最高位设置为1,反之为0

按照前面的假设:二进制位数为n,其中m位用于表示数据,k位用来奇偶校验。这就产生了一个冗余率:

R = n / m = ( m + k ) / m = ( m + 1 ) / m = 1 + 1 / m R=n/m=(m+k)/m=(m+1)/m=1+1/m R=n/m=(m+k)/m=(m+1)/m=1+1/m

这个没什么好讲的。很简单,近百年前的机器上就已经应用了这种技术。随着时代的发展,发送的数据量增加,导致出现问题的可能性越来越高,所以要有新的技术。

举一个最小的例子:我们要发送1,奇偶校验码此时也为1,也就是说我们发送的是11

发送:11
接受:10

结果奇偶校验码与实际情况不同,所以有错,但是无法纠正。

单个错误纠正码

为了纠正错误,就要知道在哪错的。如何做到这点呢?

别忘了我们使用的是二进制,我们要知道的位置就是第几位。

汉明引入了一个叫做检查数(Checking Number)的概念,其实就是按一定顺序进行多次奇偶校验,也是汉明码最神奇的地方。

讲奇偶校验码的时候,提到只能知道有一位不对,那怎么知道谁是不对的一位呢?

这里以 4 位二进制数12为例,也就是1100。由于要找到是 4 位中的哪个出现了问题,mk满足以下公式(为什么后面会说)。其中m位用于表示数据,k位用来校验和纠错:

2 k ≥ m + k + 1 2^k \ge m+k+1 2km+k+1

所以需要 3 个额外的奇偶校验位来找到它。

也就是说我们需要传输 7 位,这个很关键,一定要搞清楚位数的变化。因为现在起我们考虑一位出错的时候,需要考虑到这些校验码。

那么在最多只有一位出错的情况下,有 8 种可能:没出错,或第 1 ~7 位中某一个出错。

汉明真的是非常厉害,他使用了一个很简单的方法:你不好哪一位出错,那就把它分成一位找。先看内容二进制的最右边一位:

	 |
1=0001
3=0011
5=0101
7=0111
(这里取07之间的,也就是上面可能情况的范围)

那么可以得到 1、3、5、7,然后再取两个(因为一共三个校验位):

	|
2=0010
3=0011
6=0110
7=0111

   | 
4=0100
5=0101
6=0110
7=0111

把这三组数写一起:

取第一位:1   3   5   7
取第二位:  2 3     6 7
取第三位:      4 5 6 7

你会发现这三组数覆盖了 1~7 这个范围。

此外,你会发现如果只取两位,会少一个数没有覆盖到。如果取四位,就多余了,因为三位已经全覆盖了。所以可以得到前面的那个关系:

2 k ≥ m + k + 1 2^k \ge m+k+1 2km+k+1

也可以知道这里的1就表示的是没出错的情况。

然后汉明对则三组对应的数进行奇偶校验,奇偶校验结果存放的位置就是上面每组的第一个数字,如下(x是校验位,目前还不知道呢):

序列:   x x 1 x 1 0 0
取第一位:1   3   5   7	--- 偶校验,得0

序列:   0 x 1 x 1 0 0
取第二位:  2 3     6 7   --- 奇校验,得1

序列:   0 1 1 x 1 0 0
取第三位:      4 5 6 7   --- 奇校验,得1 

最终序列:0 1 1 1 1 0 0

这个结果和论文中的一模一样:

请添加图片描述

那么如何使用这个结果呢?

假设第五位出现了问题:

        |
0 1 1 1 0 0 0

接收方根据位数的到校验位是三个,也就是奇偶检查三次。检查方法和生成方法一模一样:

序列:   0 1 1 1 0 0 0
取第一位:1   3   5   7	--- 奇校验,得1
检查数:1
序列:   0 1 1 1 0 0 0
取第二位:  2 3     6 7   --- 偶校验,得0
检查数:0 1(注意是插入到前面了)
检查数:   0 1 1 1 0 0 0
取第三位:      4 5 6 7   --- 奇校验,得1 
检查数:1 0 1

二进制101转换成十进制就是5,出错的就是第五位。这个101就是前文提到的检查数(Checking Number),负责提供检查的位置。

再来看一个例子:如果没出错,结果是什么样的呢?

序列:   0 1 1 1 1 0 0
取第一位:1   3   5   7	--- 偶校验,得0

序列:   0 1 1 1 1 0 0
取第二位:  2 3     6 7   --- 偶校验,得0

序列:   0 1 1 1 1 0 0
取第三位:      4 5 6 7   --- 偶校验,得0

检查数:000

没出错得到的是0000也不在 1~7 的范围内。

这太神奇了是不是,怎么咔咔两边一转换,就得到错误的位置了呢?

让我们回到前面那三组数:

取第一位:1   3   5   7
取第二位:  2 3     6 7
取第三位:      4 5 6 7

这三组数只和位数有关,和你要传输的内容是不是没有任何关系。好,我们研究这组数本身。

假设第一组四个位置中有出错了。那么我们可以从其余两组知道,3、5、7是没错的,所以第一位出了错。和我们得到的最后二进制序列001是一样的。

因为通过这三组数,我们可以确定唯一的一个数,所以前面要刚刚好全覆盖,不能少也不能多。

此外这三组数如果你画个图,就和维基百科汉明码的那个图一样,最后的交集是唯一的,也就是出错了的数:

请添加图片描述

单个错误纠正加双错误检测码

单个错误纠正和双错误检测码就是在单个错误纠正码的基础上,最后多了一个奇偶校验位,用来检查前面的内容。

这里说明一下:单个错误纠正加双错误检测码并不是说在检查出来两个错误的同时,能纠正一个错误。而是要么纠正一个错误,要么检查出两个错误。

分三种情况:

  1. 没出错:如果所有的校验都成功了(也就是说都是偶校验),包括最后一个新加的校验码都过了,那么没有错误。
  2. 一个错:如果最后一个新加的校验码没过,那么检查数就是错误的位置。
  3. 两个错:如果最后一个新加的校验码过了,检查数也表示有一些错误(不为0)。

继续以前面的0 1 1 1 1 0 0为例,后面再加一个奇偶校验码之后,得到的结果是:

序列:   0 1 1 1 1 0 0 x --- 偶校验,得0

最终序列:0 1 1 1 1 0 0 0

同样假设第五位出现了问题:

        |
0 1 1 1 0 0 0 0
序列:   0 1 1 1 0 0 0 0
最后一位:     		  | --- 奇校验,得1,有可能错一个
序列:   0 1 1 1 0 0 0 0
取第一位:1   3   5   7	--- 奇校验,得1
检查数:1
序列:   0 1 1 1 0 0 0 0
取第二位:  2 3     6 7   --- 偶校验,得0
检查数:0 1(注意是插入到前面了)
检查数:   0 1 1 1 0 0 0 0
取第三位:      4 5 6 7   --- 奇校验,得1 
检查数:1 0 1             --- 检查数不为0,表示确实错一个,可以纠正

同样纠正第五位。

现在假设错了第二、五位:

  |     |
0 0 1 1 0 0 0 0

那么:

序列:   0 0 1 1 0 0 0 0
最后一位:     		  |  --- 偶校验,得0,有可能没错,有可能两个错
序列:   0 0 1 1 0 0 0 0
取第一位:1   3   5   7	--- 奇校验,得1
检查数:1
序列:   0 0 1 1 0 0 0 0
取第二位:  2 3     6 7   --- 奇校验,得1
检查数:1 1(注意是插入到前面了)
序列:   0 0 1 1 0 0 0 0
取第三位:      4 5 6 7   --- 奇校验,得1 
检查数:1 1 1

这里通过检查数还是找到了一个错误。

汉明距离

一组二机制数中,如果有 1 位不同的,Hamming 将其称作距离 1。同理有两位不同就是距离 2,以此类推。现在的汉明距离是他人叫的,而不是论文里的。

汉明将一组二进制数当作 n 维空间中的一个向量。然后通过观察编码中 1 个错误改变一个坐标,2 个错误改变两个坐标得到一个矩阵。这个矩阵就叫做距离(distance), D ( x , y ) D(x,y) D(x,y),也就是汉明距离。

此外,汉明距离也被称为将一个字符串更改为另一个字符串所需的最小替换单元(原始论文中用等价类表示的)。

一个编码全错的时候是无法检查出错误的。

  • 如果要检查出d位的错误,那么汉明距离为d+1
  • 如果要纠正d位的错误,那么汉明距离为2d+1

希望能帮到有需要的人~

参考资料

《Error detecting and error correcting codes》:1950 年汉明码的原始论文。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值