如果一个值有偶数个'1'位,则其具有偶校验。如果一个值有奇数个'1'位,则其具有奇校验。例如,0110
具有偶校验,1110
具有奇校验。
如果 x
具有偶校验,则我必须返回 1
。
int has_even_parity(unsigned int x) {
return
}
如果一个值有偶数个'1'位,则其具有偶校验。如果一个值有奇数个'1'位,则其具有奇校验。例如,0110
具有偶校验,1110
具有奇校验。
如果 x
具有偶校验,则我必须返回 1
。
int has_even_parity(unsigned int x) {
return
}
x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x ^= x >> 2;
x ^= x >> 1;
return (~x) & 1;
假设您知道整数是32位的。
GCC内置了内置函数来实现这个功能:
内置函数:
int __builtin_parity (unsigned int x)
返回
x
的奇偶性,即x中1位数模2的余数。
对于unsigned long
和unsigned long long
,也有类似的函数。
即此函数的行为类似于has_odd_parity
。 对于has_even_parity
,请反转该值。
在GCC上,这些应该是最快的替代方案。 当然,其使用不是可移植的,但您可以在您的实现中使用它,例如通过宏进行保护。
以下答案毫不掩饰地直接摘自Sean Eron Anderson(seander@cs.stanford.edu)的Bit Twiddling Hacks
使用乘法计算单词的奇偶性
以下方法仅使用8个操作就可使用乘法计算32位值的奇偶性。
unsigned int v; // 32-bit word
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x11111111U) * 0x11111111U;
return (v >> 28) & 1;
unsigned long long v; // 64-bit word
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x1111111111111111UL) * 0x1111111111111111UL;
return (v >> 60) & 1;
Andrew Shapira于2007年9月2日提出了这个想法并将其发送给我。
尝试:
int has_even_parity(unsigned int x){
unsigned int count = 0, i, b = 1;
for(i = 0; i < 32; i++){
if( x & (b << i) ){count++;}
}
if( (count % 2) ){return 0;}
return 1;
}
为了概括TypeIA的回答适用于任何体系结构:
int has_even_parity(unsigned int x)
{
unsigned char shift = 1;
while (shift < (sizeof(x)*8))
{
x ^= (x >> shift);
shift <<= 1;
}
return !(x & 0x1);
}
x & ( x - 1 )
取消最右边的 '1' 位。假设 x = 13(1101),则 x & ( x - 1 )
的操作为 1101 & 1100
,结果为 1100,注意最右边的已设置的位被转换为 0
。x
是 1100
。再进行一次 x & ( x - 1 )
操作,即 1100 & 1011
,结果为 1000
。注意原始的 x
是 1101
,经过两次 x & (x - 1)
操作后,x
变成了 1000
,也就是说,在两次操作后,有两个设置的位被移除了。如果经过奇数次操作之后,x
变成了零,则它是奇校验,否则它是偶校验。char
的#define
代码。#define PARITY(x) ((~(x ^= (x ^= (x ^= x >> 4) >> 2) >> 1)) & 1) /* even parity */
int main()
{
char x=3;
printf("parity = %d\n", PARITY(x));
}
它非常便携且易于修改以适应更大的单词(16、32位)。还要注意,使用#define
可以加快代码速度,每个函数调用都需要时间来推动堆栈和分配内存。代码大小不会受到影响,特别是如果它只在您的代码中实现了几次-函数调用可能占用与XOR一样多的目标代码。
不可否认,通过使用此功能的内联函数版本,可以获得相同的效率,inline char parity(char x) {return PARITY(x);}
(GCC)或__inline char parity(char x) {return PARITY(x);}
(MSVC)。假设您保留了一行定义。
int parity_check(unsigned x) {
int parity = 0;
while(x != 0) {
parity ^= x;
x >>= 1;
}
return (parity & 0x1);
}
.code
; bool CheckParity(size_t Result)
CheckParity PROC
mov rax, 0
add rcx, 0
jnp jmp_over
mov rax, 1
jmp_over:
ret
CheckParity ENDP
END
这是我在64位C程序中使用的一段代码,用于检查计算结果的奇偶性,编译器使用MSVC。您可以将其移植到32位或其他编译器。
这种方法比使用C语言更快,并且利用了CPU的功能。
这个例子的作用是将一个参数作为输入(通过RCX - __fastcall调用约定传递)。它将其增加0,从而设置CPU的奇偶标志,然后将变量(RAX)设置为0或1,如果奇偶标志打开或关闭。
add rcx,0
是更新标志位的不幸选择,只需要 test ecx,ecx
就足够了(因为奇偶校验标志位仅从8位计算,所以测试 rcx
的哪个部分并不重要,而 ecx
是短的机器码)。而 jnp
比没有跳转的 setp
更慢。通常大多数 C 编译器都会有内置的内部函数,这绝对是避免在3行代码中出现一些小错误的最佳(也是最快)选择...(就像这里演示的那样)。 - Ped7g