海明编码与检验原由
以内存为例, 如果内存所处的电磁环境比较复杂, 或者空间环境下受到带电粒子的打击, 那么可能导致电容的充放电或者触发器的翻转(SRAM)。 这样会导致存储信息的改变。 如果不校验, 存储中存储的程序可能不会发挥它应有的作用, 甚至会发生严重的后果。

编码的最小距离
任意两组合法代码之间二进制位数的最小差异、编码的纠错、改错能力与编码的最小距离有关。 编码的最小距离就是从一种合法代码转化成另外一种合法代码所变化的最小位数。存在如下公式:
L−1=C+D(D≥C)L-1=C+D(D\geq C)L−1=C+D(D≥C)汉明码是一种具有纠错能力的编码。其中:

L:L:L:编码的最小距离
D:D:D:检测错误的位数(信息位)
C:C:C:纠正错误的位数(校验位或冗余位)

冗余位
冗余位”是一种二进制位,它被用来添加到需要传输的数据信息中,以确保信息在传输过程中不会发生丢失或者改变。

对于“冗余位”究竟需要多少位这个问题,我们有一个公式可以用来计算:
2r≥m+r+12^r\geq m+r+12r≥m+r+1其中rrr是冗余位,mmm为数据位。rrr指的是冗余位究竟需要多少位,而mmm指的是传输的数据的二进制位数。

假设传输的数据的二进制位数是7位,那么冗余位的个数就可以通过上面的公式来计算:=24≥7+4+1= 2^4 ≥ 7 + 4 + 1=24≥7+4+1因此,我们的至少需要4个二进制位作为“冗余位”。

对比以上两种概念,可看出冗余位等价于纠正错误的位数

(注意:汉明码默认一串数据只错一位)

奇偶校验位
奇校验: 在奇校验检测方式中,对于需要发送的数据信息比特,检查其中1的个数。如果这串比特中1的个数是奇数,为了保证加上“冗余位“后,””整串数据中1的个数最后为奇数,可想而知,冗余位上应该设置为“0”。如果在没有添加“冗余位”之前,数据比特流中的1的个数为偶数,那么为了最后把1的个数凑成一个奇数,冗余位上应该设置为1。
偶校验: 同理,在偶校验检测方式中,对于需要发送的数据信息比特,仍然检查其中1的个数。如果这串比特中1的个数是奇数,为了保证加上“冗余位“后,””整串数据中1的个数最后为偶数,可想而知,冗余位上应该设置为“1”。如果在没有添加“冗余位”之前,数据比特流中的1的个数为偶数,那么为了最后把1的个数凑成一个偶数,冗余位上应该设置为0。例如(偶校验):

如果整个代码“1”的个数为奇数, 我们就知道有一位数据发生了翻转(因为数据位翻转的位数越多, 可能性越小。)如果我们将数据划分成为两组,每组都加一个校验位,那么可以大大缩小确定发生翻转的位数的范围。这种划分方式是没有重叠的, 每个分组的数据连在一起就是原来的数据。

但海明码并未使用上述分组原理。

海明码分组原理
汉明码采用的是非划分方式。对于下面这个数据, 我们采用汉明码的方式。

将数据分为三组, 每组一个校验位, 每组四位数据。 按照如下方式分组

(注意:上、左、右三个圆分别表示P1、P2、P3组) 把表示位置的这个数,转化成二进制数。也就是,

第1个位置,变成第0001个位置;
第2个位置,变成第0010个位置;
第3个位置,变成第0011个位置;
第4个位置,变成第0100个位置;
第5个位置,变成第0101个位置;
第6个位置,变成第0110个位置;
第7个位置,变成第0111个位置;

那么,规定来了,
凡是位置符合这种形式的,XXX1,归到P1;
凡是位置符合这种形式的,XX1X,归到P2;
凡是位置符合这种形式的,X1XX,归到P3;
凡是位置符合这种形式的,1XXX,归到P4;

则上图中:
位置在1、3、5、7的数据进入组P1;
位置在2、3、6、7的数据进入组P2;
位置在4、5、6、7的数据进入组P3;
没有数据进入组P4;

若某个组位置错了将其置为1,没错就是0,则有:

P3 P2 P1 错位的位置号
0 0 0 无差错
0 0 1 1
1 0 1 5
1 1 0 6
1 1 1 7

可以看出P3、P2、P1组成的二进制值就是发生错误的位置。记住规定,在采用汉明码的一串数据中,2i2^i2i的位置上,我们放校验码。


海明码编码和校验实例(以奇校验为例)
编码:
假定数据为:1011001。由于24≥7+4+12^4 ≥ 7 + 4 + 124≥7+4+1,因此需要4位校验位或冗余位。填充冗余位后有:

  • 对于第一组来说(1,3,5,7,9,11位为一组):1的个数为4个,偶数个,因此①号应该为1。这样1的个数最后才能保证为奇数。
  • 同理,对于第二组来说(2,3,6,7,10,11位1组):1的个数为3个,已经是奇数了,因此②号应该是0。
  • 对于第三组来说(4,5,6,7位一组),1的个数为1个,因此,③号应该是0。
  • 对于第4组来说(8,9,10,11为一组),1的个数为2个,因此,④应该为1。
  • 最后,总的汉明码就构造完毕了,如下所示:

    校验:
    上面,我们已经完成了“汉明码”的编码,那么,汉明码又是如何发现错误以及改正错误的呢?
    假设,第“5”号位上的“0”在传输过程中变成了“1”,接收方收到的数据则为:10111010101。

    汉明码通过检查每一小组的“奇校验”,来确定是否发生了错误。
  • 首先第一组(1,3,5,7,9,11位):1的个数为6位,不再是奇数个了,因此,我们可以断定,这一组中肯定有某个数据发生了错误,但不能确定是哪一位上发生了错误。为了达到“奇校验”,我们必须补1个1来达到奇数个1。
  • 接下来,我们检查第二组(2,3,6,7,10,11) ,1的个数为3位,仍然满足“奇校验”,因此我们也可以断定这一组中没有任何一位数据发生了改变。所以,我们只需要补0。
  • 我们继续检查第三组(4,5,6,7),1的个数为2个,不在满足“奇校验”,因此,我们可以断定,这一组中也有数据发生改变。为了达到“奇校验”,我们必须补1个1来达到奇数个1。
  • 我们检查第4组(8,9,10,11位),1的个数为3位,满足“奇校验”,因此没有发生改变。所以我们只需要补0。
    如下图所示:

    最后得出来的二进制数是:0101,我们会神奇地发现,0101就是10进制5的二进制表现,因此,我们可以准确的知道,5号位上发生了数据的改变,我们只要对5号位进行置反操作即可。最后,接收方就可以修改成为正确的数据啦。

海明码编码和校验实例(以偶校验为例)
编码(通常汉明编码是以偶校验进行编码的):
假定数据为:10011010,由于24≥8+4+12^4 ≥ 8 + 4 + 124≥8+4+1,因此需要4位校验位或冗余位。填充冗余位后有:
_ _1_001_1010
分组情况如下:
组数是这样的:
P1: 1,3,5,7,9… 检验奇数位
P2: 2,3,6,7,10,11… 检验两个,跳过两个,检验两个,跳过两个
P3: 4,5,6,7,12,13,14,15… 检验4个,跳过4个
P4: 8,9,10,11,12,13,14,15… 检验8个,跳过8个
由于进行偶校验,要求每个组中1的个数是偶数,因此有:

  • 第1组检验位为 1,3,5,7,9,11:
    ? _ 1 _ 0 0 1 _ 1 0 1 0. 看看1,3,5,7,9,11位,发现正好是偶数个1,所以校验位1设为0就行了:
    0 _ 1 _ 0 0 1 _ 1 0 1 0
  • 第2组检验位为 2,3,6,7,10,11:
    0 ? 1 _ 0 0 1 _ 1 0 1 0. 发现是奇数个1,于是设置校验位2为1,这样算上校验位的1,恰好是偶数个0 1 1 _ 0 0 1 _ 1 0 1 0
  • 第3组检验位为 4,5,6,7,12:
    0 1 1 ? 0 0 1 _ 1 0 1 0. 发现是奇数个1,于是设置校验位4为 0 1 1 1 0 0 1 _ 1 0 1 0
  • 第4组检验位为 8,9,10,11,12:
    0 1 1 1 0 0 1 ? 1 0 1 0. 发现是偶数个1,于是设置校验位8为 0 1 1 1 0 0 1 0 1 0 1 0
  • 最后配置好的汉明码: 011100101010.

校验:
如我们传送的011100101010,但接收到的是011100101110 (第10位出现错误)。

出错位可以这样确定:
对接受到的汉明码011100101110 进行每一个校验码的验算,即它所在的组(包括它,与之前不同的是,之前校验码是待定的,现在已经有值了)的1的个数应该是偶数个,这就暗示我们将要覆盖这个值(实际上并不是,仅仅是验算)的新校验码应该是0才对,但是由于接收到的有错误,我们在验算中发现有的校验位要填1。

这里,验算后发现第2个和第8个校验位要填1,那么错误的数据位就是2+8=10。


海明码编码和校验实现(C++\C)

#include <stdio.h>
#include <stdlib.h>//调用system函数
#include <malloc.h>
#include <math.h>
#include <dos.h>//注意pow(double,int)而不是pow(int,int)
#define M 100 //最大的数据位数
#define N 50//最大的校验位数struct Hamming{int flag;int value;//海明码的数值
}H[M];//存放海明码信息int P[N];//存放校验位信息
int C[N];//存放检验位信息
int m[M + N];//存放需要纠正的海明码
int DC = 0, PC = 0, EC = 0, HC = 0, ERROR = 0, ERROR1 = 0;//DC是数据的位数,PC是校验位的位数,不能在此更改这些数据的值,否则出错void showInf(){//显示信息printf("-------------------------------------------------------------------------------\n");printf("*****************************************海明码********************************\n");printf("***************************************输入格式如下:***************************\n");printf("*****************************如果要输入1101,需输入 1 1 0 1 -1******************\n");printf("**************输入数据 1 1 0 1 -1的过程中,不能回退删除,否则会发生错误*********\n");printf("-----------------------------选择操作:----------------------------------------\n");printf("1 输入数据后生成海明码 2 输入海明码  3 清屏  4 纠正海明码 5 返回主页 6 结束程序\n\n");printf("请选择操作,只能输入一个数: ");
}int inputData(int choice){//输入数据或海明码,参数是1就表示输入的是数据,参数是2就表示输入的是海明码。返回-1就表示输入数据错误。int data, i = 1;scanf("%d", &data);if (data != 0 && data != 1){system("cls");printf("\n\n提示信息:输入格式不正确,第一位只能是0或1,请重新选择操作\n\n\n");return -1;}DC = 1;PC = 1;while (data != -1){if (pow(2.0, PC - 1) != i){//存放数据值到海明码结构体中H[i].flag = 0;//数据位,位置标记为0H[i].value = data;m[i] = data;DC++;scanf("%d", &data);}else if (pow(2.0, PC - 1) == i&&choice == 1){//设置校验位H[i].flag = 1;//校验位,位置标记为1PC++;}if ((pow(2.0, PC - 1) == i) && choice == 2){//把海明码中的校验位放到校验位数组中,以便用这个校验位和利用数据生成的校验位异或来计算哪一位出错H[i].flag = 1;P[PC++] = data;m[i] = data;scanf("%d", &data);}i++;}//累计次数是多加了一次,减回来。DC--;PC--;if (PC + DC < 3)ERROR = 2;return 0;
}void caculateHammingCode(){//根据海明码结构体中数据位的数据值计算海明码,并把正确的海明码放到海明码结构体中。int m, j, k, temp = 0;for (m = 3; m <= DC + PC; m++){temp = 0;if (H[m].flag == 0){//数据位for (j = PC; j >= 1; j--){k = (int)pow(2.0, j - 1);if (k < m){H[k].value = H[k].value^H[m].value;temp = k;break;}}for (k = j - 1; k >= 1; k--){if (H[k].flag == 1){//校验位if (temp + pow(2.0, k - 1) == m){H[k].value = H[k].value^H[m].value;break;}if (temp + pow(2.0, k - 1) < m){H[k].value = H[k].value^H[m].value;temp = temp + pow(2.0, k - 1);}}}}}
}void caculateC(int pc){//计算检验位的值,并放到检验位的数组中。接受的参数是校验位的个数int i, k;for (i = 1; i <= pc; i++){k = (int)pow(2.0, i - 1);C[i] = P[i] ^ H[k].value;}
}void initial(){//使海明码结构体清零int i;for (i = 1; i <= DC + PC; i++){H[i].value = 0;}
}void showHammingCode(int dc, int pc){//打印海明码结构体中的值。接受的参数是dc为数据位的个数,pc为校验位的个数。int i;printf("\n\n生成的海明码为:\n");for (i = 1; i <= dc + pc; i++){printf("第%d位:", i);printf("  %d\n", H[i].value);}printf("\n");
}
void judge(int pc){//判断出哪一位出错,并打印出这一位是数据位还是校验位int i, result = 0, flag = 0;//system("cls");for (i = 1; i <= pc; i++){if (C[i] == 1) flag++;}for (i = 1; i <= pc; i++){if (flag == 0)result = result + C[i] * pow(2.0, pc - i);else result = result + C[i] * pow(2.0, i - 1);}if (result != 0){printf("\n\n\n提示信息:第%d位出错,", result);EC = result;if (flag >= 2)printf(" 这一位是数据位!\n\n");else printf(" 这一位是校验位!\n\n");}else printf("\n\n提示信息:海明码正确!\n\n\n");
}
void mend(int mc){//纠正错误的海明码。并打印出纠正前错误的海明码和纠正后正确的海明码int i, k = 0, p = 1;if (EC == 0){printf("\n\n提示信息:海明码正确或者已经纠正或者海明码为空,请重新选择操作\n\n\n");return;}system("cls");printf("\n提示信息:海明码第%d位有错误\n\n", EC);printf("\n输入的错误的海明码是:\n\n");for (i = 1; i <= mc; i++)printf("第%d位%d\n", i, m[i]);m[EC] = !m[EC];printf("\n\n纠正后的正确的海明码是:\n\n");for (i = 1; i <= mc; i++)printf("第%d位%d\n", i, m[i]);
}void run(int command){//运行不同的操作模式,command为1表示输入的数据位,command为2表示输入的是海明码int i;if (command == 1){//输入的是数据printf("\n\n请输入数据,以-1做结束符:");i = inputData(1);//返回输入的数据位数if (i == -1) return;caculateHammingCode();showHammingCode(DC, PC);initial();HC = PC + DC;DC = 0;PC = 0;}else {//输入的是海明码printf("\n\n请输入海明码,以-1做结束符,只能有一位错误:");i = inputData(2);if (i == -1) return;caculateHammingCode();if (ERROR == 1 || ERROR == 2) {system("cls");printf("\n\n提示信息:输入格式不正确,第一位只能是0或1,并且输入的位数要大于等于3.请重选操作\n\n\n");ERROR = 0;PC = 0;return;}caculateC(PC);judge(PC);initial();HC = PC + DC;PC = 0;DC = 0;}
}
void main(){int function, flag = 1, command, md = 0, back = 0;showInf();scanf("%d", &function);while (flag){switch (function){case 1: command = 1;run(command);//输入数据md = 0;break;case 2: command = 2;//输入海明码run(command);md = 1;break;case 3: system("cls");//清屏break;case 4:system("cls");if (md == 1)//纠正海明码mend(HC);else printf("\n\n提示信息:您还没有输入海明码或者输入的海明码已经被纠正了.\n\n\n");md = 0;EC = 0;break;case 5: system("cls");//返回主页back = 1;break;case 6:exit(1);//退出default: system("cls");printf("\n\n\n提示信息:操作不正确,请重新选择!\n\n");break;}if (back == 1){showInf();back = 0;}else {printf("\n1 输入数据后生成海明码 2 输入海明码  3 清屏  4 纠正海明码 5 返回主页 6 结束程序\n\n");printf("请选择操作,只能输入一个数: ");}scanf("%d", &function);}
}

测试:
以数据10011010进行测试,结果如下:

海明编码结果为:011100101010
如我们传送的011100101010,但接收到的是011100101110 (第10位出现错误)。校验如下:

纠正结果如下:

接收到的是011100101110 (第10位出现错误),但实际传送的011100101010


以上博文整理自:

  1. williamgavin_存储器(四)-- 汉明码
  2. 刘扬俊_汉明码 – 计算机网络 – 全网最通俗的讲解
  3. Vic_Chen_is_here_存储器的校验–汉明码(Hanming Code)
  4. flysky2011_海明码的改进算法,请多多指教!

海明码编码和校验原理与实现【转载】相关推荐

  1. 易理解的海明码的编码和校验原理【转载】

    海明码简单分析(方法1) 海明码(也叫汉明码)具有一位纠错能力.本文以1010110这个二进制数为例解释海明码的编码和校验方法. 编码 确定校验码的位数x 设数据有nnn位,校验码有xxx位.则校验码 ...

  2. 解释一下 海明码 和 海明码的工作原理

    海明码(Hamming)是能进行检错和纠错的一种编码方法. 要能纠错就需要知道哪一位发生错误,海明码就可以检测出哪一位发生了错误. 例如一个信息码长m位,加入k个校验码后,整个数据长度为(m+k)个. ...

  3. 【计算机网络】数据链路层 : 差错控制 ( 纠错编码 | 海明码 | “海明码“ 原理 | “海明码“ 工作流程 | 确定校验啊位数 | 确定校验码和数据位置 | 求校验码值 | 检错纠错 )★

    文章目录 一. "海明码" 工作原理 二. "海明码" 工作流程 三. 确定校验码位数 四. 确定校验码和数据位置 0. 确定校验码位置 1. 引入二进制位 2 ...

  4. 简单易懂的汉明码(海明码)校验原理

    汉明码编码原理 汉明码也叫做海明码,它通过向原始数据中添加校验数据来进行查错和纠错.具体来说, 假设数据位有n位,则校验位为k,k满足 2^k >= n+k+1 汉明码的位数为n+k,且校验位位 ...

  5. C语言四位海明码编码,汉明码C语言实现

    一.通信相关知识 数字通信时候从差错控制角度看,信号可以分为三类: 1.随机信道--------在随机信道中,错误码出现时随机的,且错误码之间是统计独立的: 2.突发信道--------错误码是成串集 ...

  6. QR二维码编码解码原理算法介绍

    一.什么是二维码: 二维码 (2-dimensional bar code),是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的. 在许多种类的二维条码中,常用 ...

  7. c语言海明校验码编码,海明校验码的编码规则有哪些?

    在海明码中, 位号数(1.2.3.--.n)为2的权值的那些位,即: 1(2^0).2(2^1).4(2^2).8(2^3).-2^(r-1)位,作为奇偶校验位,并记作: P1.P2.P3 .P4.- ...

  8. 计算机组成原理课程设计海明码,海明码生成与校验电路的设计

    海明码生成与校验电路的设计 沈阳航空航天大学 课课 程程 设设 计计 报报 告告 课程设计名称:计算机组成原理课程设计计算机组成原理课程设计 课程设计题目:海明码生成与校验电路的设计海明码生成与校验电 ...

  9. 图解奇偶校验与海明码的详细过程

    文章目录 1.校验码的基本概念 2.奇偶校验码 3.海明码 3.1 校验码的个数 3.2 校验码的位置 3.3 校验关系 3.4 计算校验码的值 3.5 检错与纠错 1.校验码的基本概念 名不正则言不 ...

最新文章

  1. Exchange 2010和Exchange 2016共存部署-3:Exchange2016部署系统要求
  2. 1.Redis安装以及常用命令
  3. csp-s模拟测试44「D·E·F」
  4. java张int 和 Integer的区别
  5. [20171225]变态的windows批处理4.txt
  6. matlab矩阵乘法不同行,矩阵乘法在numpy/matlab/数学上的不同
  7. RHCE-ansible第二次实验,通过ansible远程yum安装
  8. 运维审计新形势下CIO的管理职责
  9. Codeforces1380 D. Berserk And Fireball(贪心)
  10. 用window调用kjb和ktr
  11. 图形化管理工具Portaniner安 以及 Docker镜像详解(三)
  12. 开关电源spice仿真与实用设计_十年电源研发工程师的10条开关电源设计实用经验...
  13. 转:成功者的第四个特征,如何与他人打交道?
  14. 爬取糗事百科段子 + 数据可视化
  15. python 中的路径. ./ .. ../的区别
  16. 计算机基础实验4,计算机基础实验 3-4 实验报告
  17. 连接Oracle时报错ora-01034与ORA-27101
  18. 51单片机基础入门(2)点灯大师:单个LED点亮、多个LED点亮、流水灯(附程序代码、解析)
  19. 什么是5G?关注MWC 2019前你需要了解这些知识
  20. 红橙黄绿蓝靛紫-RGB-十六进制

热门文章

  1. 原来浏览器原生支持JS Base64编码解码
  2. Spring IoC,Spring Bean示例教程
  3. Docker上部署MariaDB
  4. ogg mysql表结构不一致_OGG-01163 Bad column表结构一致、trail文件meta不一致处理
  5. 【提交PR】如何在 GitHub 提交第一个 pull request
  6. linux查看openjdk的安装的路径
  7. C#LeetCode刷题之#257-二叉树的所有路径(Binary Tree Paths)
  8. C#LeetCode刷题之#326-3的幂(Power of Three)
  9. 这个世界上不止有Mysql,还有很多ClickHouse们
  10. freecodecamp_关于freeCodeCamp-常见问题