计算机在数据传输方面,为了防止传输过程中丢失数据等异常情况发生,往往需要进行内容校验,今天就和大家说说错误检测与矫正。

具体的实现很简单——在传输的数据中加入一些校验位数。

那么这些校验位数是如何工作的呢?我们就从最简单的校验方式开始说起。

  • 奇偶校验码(Parity bit)
  • 数据传输对于计算机而言就是二进制传输,每一位就是一个bit,奇偶校验最大的特点就是只需要增加一个bit即可进行校验。奇偶校验位是对给定位数的二进制数中1的个数是奇数还是偶数的二进制数,它有两种类型——奇校验位和偶校验位。如果一组给定数据位中1的个数是奇数,那么偶校验位就置为1,从而使得总的1的个数是偶数。如果给定一组数据位中1的个数是偶数,那么奇校验位就置为1,使得总的1的个数是奇数。


    奇偶校验位的作用是,保证二进制数据中出现的1的个数是奇数或者偶数。

    如下这些例子,红色位表示校验位,黑色位表示真实传输数据。

    原始数据 1的个数 奇校验 偶校验
    0000000 0 00000001 00000000
    1000011 3 10000110 10000111
    1100011 4 11000111 11000110
    1111111 7 11111110 11111111

    奇偶校验位可以检测数据传输中1出现的奇偶次数是否正确,但是它并不能告诉计算机错误出在哪里,所以在应用中一旦奇偶校验检测失败,则数据全部放弃。

    我整理了奇偶校验的使用及特点:
    1. 使用一位数据能够达到的最好的校验码效果。
    2. 检测存在概率,如果丢失两个1,则无法检测。
    3. 数据传输时,不适合检测数据噪音大的场景。
    4. 实现上硬件要求友好,仅需要异或门即可实现。
    5. 不能进行纠错,出错时数据需放弃。
    6. 被广泛用于计算机硬件中,如许多微处理器的指令高速缓存中都包括奇偶校验位保护。

    在冗余磁盘阵列(RAID)中,为了保证一定的数据容错性,也会采用奇偶校验的方式,在这里被称作奇偶校验块。具体原理就是,对于给定两个数据块,通过XOR生成第三个数据块(奇偶校验块),这样如果第一个数据块丢失,则可以通过第二个数据块和第三个数据块进行复原。
    数据块1:01101101
    数据块2:11010100
    数据块3:10111001
    如果数据块1丢失,只需要将2和3进行XOR,即可得到数据块1:01101101。

  • 水平垂直奇偶校验
  • 和简单的奇偶校验位不同,还有水平奇偶校验、垂直奇偶校验和水平垂奇偶校验这三种。

    具体原理就是将数据分割成m*n的矩阵,然后进行二维度校验。通过字面意思,我们就比较清楚,水平和垂直类似只不过校验方向不同,而水平垂直奇偶校验则是两者的合体。

    通过举例大家就会明白了,假设数据是由长度为20位的二进制构成,m = 5, n = 4,则矩阵如下:

    1 0 1 1 1
    1 1 0 1 0
    0 0 0 1 0
    1 0 0 0 1

    水平奇偶校验就是根据矩阵的四行,分别生成4个独立的奇偶校验位,这里以偶校验位(浅粉色)参考:

    1 0 1 1 1 0
    1 1 0 1 0 1
    0 0 0 1 0 1
    1 0 0 0 1 0

    垂直偶校验位(浅绿色):

    1 0 1 1 1
    1 1 0 1 0
    0 0 0 1 0
    1 0 0 0 1
    1 1 1 1 0

    水平垂直偶校验位:

    1 0 1 1 1 0
    1 1 0 1 0 1
    0 0 0 1 0 1
    1 0 0 0 1 0
    1 1 1 1 0 0

    可以看出,水平垂直奇偶校验位需要m + n - 1个位,优势是可以修复单个错误位。

  • 汉明码(Hamming code)
  • 奇偶校验只能验证数据的有效性,如果检验为无效,则只能废弃无法进行很好的纠错,这个问题让汉明很不爽。

    1940年,小伙儿汉明像往常一样在贝尔实验室,运用贝尔模型V 电脑进行工作。机器输入端是依靠打孔卡,而打孔这一操作有时候会读取错误,每次错误发生就会有个小灯一闪一闪,汉明就要人工去处理下。周末不上班的时候就尴尬了,没人处理,机器只能跳过执行下一个操作。

    有个周末,汉明正好在工作,小灯一闪他就去较正一下,又一闪就再去较正一下。他感觉很不爽,工作很low,决定好好研究一个检测算法,直接检测出来错误在哪里,工作就省事多了。伟大的发明在此诞生——汉明码!!!

    汉明码有多牛逼?


    1. 汉明码是应用最广泛的校验码,如内存(RAM)普遍集成。
    2. 没有一个校验码,能在相同空间消耗的情况下,达到汉明码效果。

    如果一条信息中包多个用于纠错的位,且通过妥善安排这些纠错位使得不同的出错位产生不同的错误结果,那么我们就可以找出出错位了。在一个7位的信息中,单个位出错有7种可能,因此3个错误控制位就足以确定是否出错及哪一位出错了。汉明研究了包括五取二码在内的编码方案,并归纳了他们的想法。

    wikipedia很清楚的描述了通用算法:
    1. 从1开始给数字的数据位(从左向右)标上序号, 1,2,3,4,5...
    2. 将这些数据位的位置序号转换为二进制,1, 10, 11, 100, 101,等。
    3. 数据位的位置序号中所有为二的幂次方的位(编号1,2,4,8,等,即数据位位置序号的二进制表示中只有一个1)是校验位。
    4. 所有其它位置的数据位(数据位位置序号的二进制表示中至少2个是1)是数据位。
    5. 每一位的数据包含在特定的两个或两个以上的校验位中,这些校验位取决于这些数据位的位置数值的二进制表示。

    从图中可以看出:
    1. 校验位1覆盖了所有数据位位置序号的二进制表示倒数第一位是1的数据:1(校验位自身,这里都是二进制,下同),11,101,111,1001,等
    2. 校验位2覆盖了所有数据位位置序号的二进制表示倒数第二位是1的数据:10(校验位自身),11,110,111,1010,1011,等
    3. 校验位4覆盖了所有数据位位置序号的二进制表示倒数第三位是1的数据:100(校验位自身),101,110,111,1100,1101,1110,1111,等
    4. 校验位8覆盖了所有数据位位置序号的二进制表示倒数第四位是1的数据:1000(校验位自身),1001,1010,1011,1100,1101,1110,1111,等
    5. 简而言之,所有校验位覆盖了数据位置和该校验位位置的二进制与的值不为0的数。

    举例,对11000010进行汉明编码,求编码后的码字。