[英]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.