如何在C语言中对一个数的所有位进行异或运算?

zazmityj  于 2022-12-11  发布在  其他
关注(0)|答案(7)|浏览(163)

有没有一种简单的方法可以将一个数的所有位一起进行XOR运算,即C语言中的一元XOR运算?
具有以下效果的事物:

result = ^(0x45); // ( 0 ^ 1 ^ 0 ^ 0 ^ 0 ^ 1 ^ 0 ^ 1 = 1)
result = ^(0x33); // ( 0 ^ 0 ^ 1 ^ 1 ^ 0 ^ 0 ^ 1 ^ 1 = 0)
bkkx9g8r

bkkx9g8r1#

愚者为此提供了一个内置函数:

int xor_bits(unsigned x) {
    return __builtin_parity(x);
}

或者,您可以通过计算设置位的数量来计算奇偶校验。

int xor_bits(unsigned x) {
    return __builtin_popcount(x) & 1;
}

如果您只想使用标准C,https://graphics.stanford.edu/~seander/bithacks.htmlHow to count the number of set bits in a 32-bit integer?有一些很好的解决方案来计算设置位的数量。

uplii1fm

uplii1fm2#

时间复杂度O(n)

#include <limits.h>

int odd_parity(unsigned v) { 
    #if (UINT_MAX > 0xFFFFFFFFFFFFFFFFu)
    v ^= v >> 64;  // Prepare for the future
    #endif
    #if (UINT_MAX > 0xFFFFFFFFu)
    v ^= v >> 32;
    #endif
    #if (UINT_MAX > 0xFFFFu)
    v ^= v >> 16;
    #endif
    v ^= v >> 8;
    v ^= v >> 4;
    v ^= v >> 2;
    v ^= v >> 1;
    return (int) (v&1);
}
q7solyqu

q7solyqu3#

没有特殊的运算符。您需要手动执行此操作,如下所示:

unsigned int value = 0x45;
unsigned int result = 0;
while (value) {
    result ^= value & 1;
    value >>= 1;
}

您还可以创建一个查找表,其中包含所有1字节值的奇偶校验:

char parity[256] = { 0, 1, 1, 0, 1, 0, 0, 1,
                    ...
                     1, 0, 0, 1, 0, 1, 1, 0 };
yhxst69z

yhxst69z4#

如果您使用gnu gcc,您应该可以使用__builtin_popcount来计算on位的数目(即位设为1)。XOR的结果将是这个数的奇偶性。但是这个解决方案没有使用标准,并且不会总是有效。
我认为,只使用标准是不存在完美解决方案的。

z5btuh9x

z5btuh9x5#

如果二进制表示中1的数目是奇数,则答案是1 ;如果是偶数,则答案为0

jtw3ybtb

jtw3ybtb6#

试试这个:

unsigned long parity(unsigned long x) {
    for(char i=sizeof(unsigned long)<<2;x>1;i>>=1) x=(x^(x<<i))>>i;
    return x;
}

unsigned long是支持的最大类型(unsigned long long是可能的最大类型)。它在<cstdint> or <stdint.h>中定义。sizeof(unsigned long)是字节。我们需要一半位来开始,所以它是字节 *4。然后,上半部分与下半部分进行异或。然后我们去掉下半部分。编辑后的答案保证了收敛,最多应该有一个溢出。

e5njpo68

e5njpo687#

你可以在一个循环中计算所有的位数,或者如果你想做一些效率更高的事情,你可以屏蔽掉原始数的一部分,然后对它们进行异或运算,反复进行,直到你得到1位的操作数。假设一个32位整数用2的补码表示:

int xor_all(int v)
{
    int l = (v & 0xFFFF0000) >> 16;
    int r = v & 0x0000FFFF;
    int m = l ^ r;

    l = (m & 0xFF00) >> 8;
    r = m & 0x00FF;
    m = l ^ r;

    l = (m & 0xF0) >> 4;
    r = m & 0x0F;
    m = l ^ r;

    l = (m & 0xC) >> 2;
    r = m & 3;
    m = l ^ r;

    l = (m & 2) >> 1;
    r = m & 1;
    m = l ^ r;
    return m;
}

还有其他技术也;如果你只取结果的最低位,任何计算集合位数的好的例程都可以工作。上面的代码的好处是相对容易理解,但它不太可能是最快的。
正如Peter Cordes所指出的,您可以跳过掩码(& s),直到最后一步(即用m = (l ^ r) & 1;替换m = l ^ r;,用M替换任何M/N的所有其他M & N)。我在上面留下它们,因为它们可能会使算法的工作方式更清楚。

相关问题