介绍
由Richard Hamming于1950年提出、还被广泛采用的一种很有效的校验方法,是只要增加少数几个校验位,就能检测出二位同时出错、亦能检测出一位出错并能自动恢复该出错位的正确值的有效手段,后者被称为自动纠错。它的实现原理,是在k个数据位之外加上r个校验位,从而形成一个k+r位的新的码字,使新的码字的码距比较均匀地拉大。把数据的每一个二进制位分配在几个不同的偶校验位的组合中,当某一位出错后,就会引起相关的几个校验位的值发生变化,这不但可以发现出错,还能指出是哪一位出错,为进一步自动纠错提供了依据。
代码:
#include<bits/stdc++.h>
using namespace std;
class Ham {
public:
void print_16(int sum)//输出对应的十六进制值
{
if(sum<9) cout<<sum;
else if(sum == 10) cout<<"A";
else if(sum == 11) cout<<"B";
else if(sum == 12) cout<<"C";
else if(sum == 13) cout<<"D";
else if(sum == 14) cout<<"E";
else if(sum == 15) cout<<"F";
}
void print_result_16(int code_result[],int len) //按十六进制转换
{
int remain = len % 4 ;
int sum = 0;
int power = 0;
for(int i = remain ; i > 0 ; i-- )
{
sum += code_result[i]*pow(2,power++);
}
print_16(sum);
for(int i=0;i<len/4;i++)
{
sum = 0; power = 0;
for(int j = remain+i*4+4 ;j > remain+i*4;j--)
{
sum += code_result[j]*pow(2,power++);;
}
print_16(sum);
}
}
bool judge_if_1(int num,int pos)//判断某个数的某一位是否为 1
{
const int Size = 32;
char str[Size];
bitset<Size> bs(num);
strcpy(str, bs.to_string().c_str());
if(str[32-pos] == '1') return true; //如果是1,返回为真
return false;
}
void code()
{
char s[100];
cout<<"输入要转化为CRC的二进制串:"<<endl;
cin>>s;
int N = strlen(s); //待编码的串
int re[100] ;//保存结果
int count = 0;
for(int i=1,j=0 ;j < N; i++)
{
if( i & (i-1) ) //如果不是2的次幂,则将其保存在结果数组中
{
re [i] = (int)s[j]-48; j++;
}
else
re [i] = 0;
count++;//统计生成编码的长度
}
double base = 2.0;
for(double i = 0 ; i < count-N ; i++)
{
int ans = 0;
for(int j = 1; j <= count ; j++)
{
if( judge_if_1(j,i+1) == true )
{
ans = ans ^ re[j];
}
}
int k = pow(base,i);
// cout<<k<<" "<<ans<<endl;
re[k] = ans;
}
//输出编码后的结果
cout<<"二进制Hamming编码:";
for(int i=1;i<=count;i++)
{
cout<<re[i];
}
cout<<endl;
cout<<"十六进制Hamming编码:";
print_result_16(re,count) ;
cout<<endl;
}
void check_code()
{
char s[100];
cout<<"输入要检验Hamming编码的二进制串:"<<endl;
cin>>s;
int N = strlen(s); //待编码的串
int re[100] ;//保存结果
for(int i = 0 ;i < N; i++)
{
re [i+1] = (int)s[i]-48;
}
int number_2_pow = 0;
for(double i = 0 ; ; i++)
{
if(pow(2.0,i) >= N) {
number_2_pow = i;break;
}
}
int check[100], cnt = 0;
for(double i = 0 ; i < number_2_pow ; i++)
{
int ans = 0;
for(int j = 1; j <= N ; j++)
{
if( judge_if_1(j,i+1) == true )
{
ans = ans ^ re[j];
}
}
check[cnt++] = ans;
}
cout<<"校验结果:";
for(int i=cnt-1;i>=0;i--)
{
cout<<check[i];
}
cout<<endl;
int sum = 0, power = 0;
for(int i = 0 ; i < cnt ; i++ )
{
sum += check[i]*pow(2,power++);
}
if(sum == 0) cout<<"Hamming编码正确"<<endl;
else{
cout<<"Hammming编码出现错误"<<endl;
cout<<"正确Hamming编码为:";
for(int i = 0 ;i < N; i++)
{
if(i == sum-1) {
if(s[i]=='1') cout<<0;
else cout<<1;
}
else cout<<s[i];
}
cout<<endl;
}
}
};
int main()
{
Ham ham; //创建crc类
cout<<"开始程序"<<endl;
while(true)
{
cout<<"****************************************************************"<<endl;
cout<<"生成Hamming编码输入0, 检验Hamming编码输入1, 退出程序输入2:"<<endl;
int choose ;
cin>>choose;
switch(choose)
{
case 0: ham.code(); break;//生成发送的Hamming编码
case 1: ham.check_code ();break;//检验Hamming编码
case 2: return 0;
}
}
return 0;
}
/*
测试样例:
开始程序
****************************************************************
生成CRC编码输入0, 检验CRC编码输入1, 退出程序输入2:
0
输入要转化为CRC的二进制串:
1010001101
CRC编码二进制: 101000110101110
CRC编码十六进制: 51AE
****************************************************************
生成CRC编码输入0, 检验CRC编码输入1, 退出程序输入2:
1
输入要验证的二进制串:
101000110101110
其余数为:00000
通过CRC验证
****************************************************************
生成CRC编码输入0, 检验CRC编码输入1, 退出程序输入2:
1
输入要验证的二进制串:
101000110101111
其余数为:10101
CRC编码出现错误
****************************************************************
生成CRC编码输入0, 检验CRC编码输入1, 退出程序输入2:
2
*/
运行结果: