目录
前言
信息的传输都是以比特流的方式传输的,数据在传输过程中,可能存在传输错误的情况,如发送的数据是01001101,而接收到的数据是01001100,比特位出现最低位出现错误,由1变成了0。为了检测出这种错误,工程应用上通常采用奇偶校验的方式来实现。
以奇校验为例,我们传输的一个字节8比特的数据,先计算比特位1的个数,如果比特位1的个数是奇数,则第9位设置为0,如果比特位1的个数是偶数,则第9位设置为1,连续9比特的1的个数始终保持奇数。偶校验类似。
本文档主要描述计算比特位奇偶数量的方法,供开发者参考。
一、方法一
任何数字的某个比特位与1进行与操作,对应比特位结果为1,则表明比特位是1,利用这个特点,将这个数字的二进制与1进行按位与,然后将数字右移以为重复操作,最终计算出比特位1的个数。
int parity_method1(char data)
{
int i;
int n = sizeof(char);
int count = 0;
for (i = 0; i < n; i++)
{
if ((data & 1) == 1)
{
count++;
}
data = data >> 1;
}
return (count % 2); //偶数返回0,奇数返回1
}
二、方法二
举例推理,若一个数字346,对它每个位进行%10、/10操作,因为一个数%10的余数是<10,如下:
346 % 10 = 6
346 /10 = 34
34%10 = 4
34/10=3
如此,如果我们进行%2、/2操作,数字取模2的结果是1,则改为为1,依次可以计算出数字的1 的个数。
int parity_method2(unsigned char data)
{
int i = 0;
int n = sizeof(char);
int count = 0;
for(i = 0; i < n; i++)
{
if (data % 2 == 1)
{
count++;
}
data = (data>>1);
}
return (count % 2); //偶数返回0,奇数返回1
}
三、方法三
一个数字与上这个数字减一的数,该数二进制最右边的1必然会消除掉,以此类推,从右往左,每一次进行按位与操作,都会取消掉一个1,直到该数字变为0,跳出循环,就得到了该数字二进制中1的个数。
int parity_method3(unsigned char data)
{
int i = 0;
int n = sizeof(unsigned char);
int count = 0;
while (data != 0)
{
data = data & (data - 1);
count++;
}
return (count % 2); //偶数返回0,奇数返回1
}
四、方法四
#define P2(N) N,N^1,N^1,N
#define P4(N) P2(N),P2(N^1),P2(N^1),P2(N)
#define P6(N) P4(N),P4(N^1),P4(N^1),P4(N)
static const bool parity_table[256] = {P6(0),P6(1),P6(1),P6(0)}; //偶数个1parity_table[i]=0,否则parity_table[i]=1
int main(void)
{
unsigned char data = 6;
int result = 0;
result = parity_table[data & 0xff];
printf("result = %d\r\n",result);
if ( result == 0)
{
printf("偶数个1\r\n");
}
else
{
printf("奇数个1");
}
return 0;
}
而对于32-bit的数,则使用下面的代码:
unsigned int v;
v ^= v >> 16;
v ^= v >> 8;bool parity = ParityTable256[v & 0xff];
原理:
(1)通过v^=v>>16,将v中的低16位与高16位进行按位或(^)操作, 相当于0~16位保留1的总个数的奇偶与v中的1的总 个数的奇偶相同;
(2)通过v^=v>>8,将v中的9~16位与0~8位进行按位或(^)操作,相当于0~8位保留1的总个数的奇偶与0~16中1的总个数的奇偶相同;
(3)通过(1)(2)操作,最初v中1的总个数的奇偶与最后v中1~8位中1的总个数的奇偶相同,v&0xff相当于获取v中1~8比特位的1,然后再查表即可。
或者使用如下的代码:
unsigned char * p = (unsigned char *) &v;
parity = ParityTable256[p[0] ^ p[1] ^ p[2] ^ p[3]];
原理:取v的地址,并进行强制类型转换为char*,
通过p[0] ^ p[1] ^ p[2] ^ p[3]] 操作,将p[i]中的所有的1都放在一个8位的数中,然后查表即可。