簡體   English   中英

如何在C中對單個數字的所有位進行異或?

[英]How to XOR all of the bits of a single number in C?

有沒有一種簡單的方法可以將單個數字的所有位異或在一起,即 C 中的一元異或?

具有以下效果的東西:

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

GCC 有一個內置的:

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

或者,您可以通過計算設置位的數量來計算奇偶校驗。 為此 gcc 內置是__builtin_popcount()

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

如果您只想堅持使用標准 C,請訪問 https://graphics.stanford.edu/~seander/bithacks.html以及如何計算 32 位整數中設置的位數? 有一些很好的解決方案來計算設置位的數量。

沒有特殊的運算符。 您需要按如下方式手動執行此操作:

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

一種簡化的 O(log2(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);
}

如果您使用的是 gnu gcc,您應該能夠使用__builtin_popcount來計算 on 位的數量(即位設置為 1)。 XOR 的結果將是這個數字的奇偶校驗。 然而,這個解決方案沒有使用標准,並且不會總是有效。

我相信沒有僅使用標准的優雅解決方案。

如果二進制表示中 1 的數量是奇數,則答案為 1 ; 如果是偶數,則答案為 0

您可以計算循環中的所有位,或者如果您想要一些可能更有效的東西,您可以屏蔽原始數字的一部分並對它們進行異或,重復,直到您得到 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;
}

還有其他技術; 如果您只取結果的最低位,則任何用於計算設置位的良好例程都將起作用。 上面的代碼的好處是比較容易理解,但不太可能是最快的。

試試這個:

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。 然后,上半部分與下半部分進行異或。 然后我們去掉下半部分。 編輯后的答案保證收斂,最多應該有一個溢出。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM