簡體   English   中英

C - 在兩個數字之間切換一下

[英]C - Swap a bit between two numbers

我剛試過這段代碼:

void swapBit(unsigned char* numbA, unsigned char* numbB, short bitPosition)//bitPosition 0-x
{
    unsigned char oneShift = 1 << bitPosition;

    unsigned char bitA = *numbA & oneShift;
    unsigned char bitB = *numbB & oneShift;

    if (bitA)
        *numbB |= bitA;
    else
        *numbB &= (~bitA ^ oneShift);

    if (bitB)
        *numbA |= bitB;
    else
        *numbA &= (~bitB ^ oneShift);
}

交換a和b的位位置x,但由於if()我認為有更好的東西。

當我看到這個:

*numbB &= (~bitA ^ oneShift);

我真的認為有一種更簡單的方法。 如果你有東西給我,我會接受它:)

提前致謝

首先,您應該將數字中的相應位置設置為0 ,然后將其與實際位進行或運算,刪除所有條件:

*numbB &= ~oneShift; // Set the bit to `0`
*numbB |= bitA;      // Set to the actual bit value

其他數字相同。

形成面具

unsigned char mask = 1u << bitPosition;

然后通過XOR交換算法獲得對等組的憤怒。

*numbA ^= *numbB & mask;
*numbB ^= *numbA & mask;
*numbA ^= *numbB & mask;

請注意,當numbA == numbB時,這會失敗。

單個位並不比任意位掩碼容易,所以我們來談談它。 您總是可以使用1U << bitpos調用此函數。

如果兩個值中的位位置相同,則兩者中都不需要進行任何更改。 如果相反,他們都需要反轉。

XOR,1翻轉; XOR為0是無操作。

所以我們想要的是一個值為1 ,輸入之間的位差為1 ,其他地方為0。 這正是a XOR b所做的。 簡單地將其屏蔽為僅交換一些位,並且我們在3個XOR + 1 AND中進行位交換。

// call with  unsigned char mask = 1U << bitPosition; if you want
inline
void swapBit_char(unsigned char *A, unsigned char *B, unsigned char mask)
{
    unsigned char tmpA = *A, tmpB = *B; // read into locals in case A==B

    unsigned char bitdiff = tmpA ^ tmpB;
    bitdiff &= mask;               // only swap bits matching the mask
    *A = tmpA ^ bitdiff;
    *B = tmpB ^ bitdiff;
}

帶有gcc for x86-64和ARM的Godbolt編譯器瀏覽器 ,包括一個帶有unsigned而不是unsigned char的版本。)

您可以考慮if(bitdiff) { ... } ,但除非您通過避免分配來避免弄臟內存中的緩存行,否則可能不值得做任何條件行為。 使用寄存器中的值(在內聯之后),保存兩個xor指令的分支幾乎不值得。

不是xor-swap 它確實使用臨時存儲。 正如@ chux的答案所示,屏蔽的xor-swap需要3個AND操作以及3個XOR。 (和由需要用於臨時寄存器或其他存儲失敗XOR交換的唯一的好處&結果)。

此版本僅需要1 AND。 此外,最后兩個XOR彼此獨立,因此從輸入到兩個輸出的總延遲僅為3個操作。 (通常為3個周期)。


對於x86 asm示例,請參閱此代碼 - 高爾夫交換大寫字母的兩個字符串,在14個字節的x86-64機器代碼中 (帶有注釋的asm源代碼)

暫無
暫無

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

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