如何检查值是否具有奇偶校验位或奇数?

时间:2014-02-07 02:08:03

标签: c bits

如果偶数为1位,则值具有偶校验。如果具有奇数1位,则该值具有奇校验。例如,0110具有偶校验,1110具有奇校验。

如果1具有偶数奇偶校验,我必须返回x

int has_even_parity(unsigned int x) {
    return 
}

9 个答案:

答案 0 :(得分:54)

x ^= x >> 16;
x ^= x >> 8;
x ^= x >> 4;
x ^= x >> 2;
x ^= x >> 1;
return (~x) & 1;

假设你知道整数是32位。


让我们看看它是如何工作的。为了简单起见,让我们使用一个8位整数,我们可以跳过前两个移位/异或。让我们通过 h 标记 a 位。如果我们查看我们的号码,我们会看到:

a b c d e f g h


第一个操作是x ^= x >> 4(记住我们正在跳过前两个操作,因为在这个例子中我们只处理一个8位整数)。让我们通过组合XOR一起的字母来写入每个位的新值(例如, ab 表示该位具有值 a xor b < / i>的)。

a b c d e f g h ) XOR ( 0 0 0 0 a b <我> c d

结果如下:

a b c d ae bf cg dh


下一步操作是x ^= x >> 2

a b c d ae bf cg dh ) XOR (0 0 a b c d ae bf

结果如下:

a b ac bd ace bdf aceg bdfh

注意我们如何开始累积右侧的所有位。


下一步操作是x ^= x >> 1

a b ac bd ace bdf aceg bdfh ) XOR (0 b ac bd ace bdf aceg

结果如下:

a ab abc abcd abcde abcdef abcdefgh abcdefgh


我们已经在最低有效位中累积了原始字中的所有位,XOR'd。因此,当且仅当输入字中存在偶数个1位(偶校验)时,该位现在为零。相同的过程适用于32位整数(但需要我们在本演示中跳过的那两个额外的移位)。

最后一行代码只删除除最不重要位(& 1)之外的所有位,然后翻转它(~x)。如果输入字的奇偶校验是偶数,则结果为1,否则为零。

答案 1 :(得分:5)

直接从Bit Twiddling Hacks By Sean Eron Anderson, seander@cs.stanford.edu

取消以下答案

使用乘法

计算单词的奇偶校验
  

以下方法使用乘法计算仅8个操作中的32位值的奇偶校验。

unsigned int v; // 32-bit word
v ^= v >> 1;
v ^= v >> 2;
v = (v & 0x11111111U) * 0x11111111U;
return (v >> 28) & 1;
  

对于64位,8个操作仍然足够。

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日寄给我。

答案 2 :(得分:3)

尝试:

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;
}

瓦尔特

答案 3 :(得分:2)

在GCC上有一个built-in function

  

内置函数:int __builtin_parity (unsigned int x)

     

返回x的奇偶校验,即x modulo 2中的1位数。

即。此函数的行为类似于has_odd_parity。反转has_even_parity

的值

这保证是GCC上最快的选择。当然它的使用不是那么便携,但你可以在你的实现中使用它,例如由宏保护。

答案 4 :(得分:1)

主要思想是这个。取消最右边的&#39; 1&#39;使用x & ( x - 1 )进行比特。假设x = 13(1101)且x & ( x - 1 )的运算为1101 & 1100,即1100,请注意最右边的设置位转换为0

现在x1100x & ( x - 1 )1100 & 1011的操作是1000。请注意,原始x1101,并且在x & (x - 1) x的两次操作之后1000odd,即在两次操作后删除了两个设置位。如果在x次操作之后,NSString *dateFormat = @"dd/MM/yyyy HH:mm:ss a"; NSTimeZone *inputTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; NSDateFormatter *inputDateFormatter = [[NSDateFormatter alloc] init]; [inputDateFormatter setTimeZone:inputTimeZone]; [inputDateFormatter setDateFormat:dateFormat]; **NSDate *date = [inputDateFormatter dateFromString:_strLiveStreamStartTime];** NSTimeZone *outputTimeZone = [NSTimeZone localTimeZone]; NSDateFormatter *outputDateFormatter = [[NSDateFormatter alloc] init]; [outputDateFormatter setTimeZone:outputTimeZone]; [outputDateFormatter setDateFormat:dateFormat]; NSString *outputString = [outputDateFormatter stringFromDate:date]; NSLog(@"%@",outputString); 变为零,则其为奇校验,否则为偶校验。

答案 5 :(得分:1)

概括@ TypelA对任何架构的回答:

int has_even_parity(unsigned int x) 
{
    unsigned char shift=1;
    while (shift < (sizeof(x)*8))
    {
            x ^= (x>>shift);
            shift<<=1;
    }
    return !(x & 0x1);
}

答案 6 :(得分:0)

int parity_check(unsigned x) {
    int parity = 0;
    while(x != 0) {
        parity ^= x;
        x >>= 1;
    }
    return (parity & 0x1);
}

答案 7 :(得分:0)

这是一行#define ,它可以解决char的问题:

#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)可以获得相同的效率。假设您保留一行定义。

答案 8 :(得分:-3)

这是一个相当古老的问题,但是我将这个问题发布给将来可能会使用它的人。

我不会在c中添加一个例子,因为已经有足够好的答案了。

如果最终结果应该是一段可以用c程序工作(编译)的代码,那么我建议如下:

.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

这是我用来检查使用MSVC编译的64位c程序中计算结果的奇偶校验的一段代码。您显然可以将其移植到32位或其他编译器。

这样做的好处是比使用c快得多,它还利用了cpus功能。

这个例子的作用是将参数作为输入(在RCX中传递 - __fastcall调用约定)。它将其递增0,从而设置cpus奇偶校验标志,然后如果奇偶校验标志打开则将变量(RAX)设置为0或1。