就是在 2's complement 裡面, X = X & X-1, 會移除 X 裡面最右邊的 1,
在 C 裡面, 只要在 unsigned (或者全為正數)的變數裡面, 就可以用這個方法,
主要原因, 我想應該是在 2 進位的體系下, 只要讓某個值少 1, 就會讓那個值最後的一個1的右邊數值產生借位, 而造成了一個很有趣的 Pattern如下:
01111111 127
01111110 126
.
.
.
01011000 88
01010111 87
所以 X & X-1 會把 least significant 1-bit 給 & 成 0.
然而, 這個方法在 Sign-and-magnitude 的表示法裡會踢到鐵板,
因為他的正負值差別只在 sign bit. 所以並不適用此規則,
ex:
10000010 -2
10000011 -3
x = -2; x &= x-1 ==> 可以看到, x 做完運算還是等於 -2.
最後來看個範例, 來計算一個 unsigned 變數裡有幾個 bit 被 turned on.
正常的方法來檢驗每個 bit
int bitcount(unsigned x) { int b; for (b=0; x !=0; x >>= 1) if (x & 01) b++; return b; }
用 X & X-1 trick 來做檢驗
int quickBitcount(unsigned x) { int count = 0; while (x) { x &= (x-1); count++; } return count; }
完畢, 感謝大家收看.
還是不會用 閱讀更多 的功能~ 囧rz
回覆刪除好像變魔術
回覆刪除http://realtimecollisiondetection.net/blog/?p=78
回覆刪除延伸閱讀
(我最不擅長這些了 @@)
稍微分析一下quickBitcount,假設x中0,1出現的機率一樣(也就是平均下來會有n/2個0和n/2個1,n = sizeof(x)),則需要的基本運算個數分別是:
回覆刪除CMP n/2
SHIFT 0
AND n/2
ADD(SUB) (n/2) * 2 /*for x-1 and count++*/
正常的bitcount的分析就比較複雜些,有空再來看看:D
兩個bitcount的分析來囉,一樣假設x中每個bit為0 or 1的機率各半:
回覆刪除_________quickBitcount____bitcount
CMP______(n/2) + 1________(n-1) - 1/2^n
SFT__________0___________(n-2) - 1/2^n
AND__________n/2_________(n-2) - 1/2^n
ADD__________n___________(n-2) - 1/2^n
/*n = sizeof(x)*/
/*一堆底線因為不知道怎麼在意見做格式化輸出耶*/
假設x是32 bits, 則下表可以看出兩個演算法的差別:
_________quickBitcount____bitcount
CMP__________17__________31
SFT___________0__________30
AND__________16__________30
ADD__________32__________30
在RISC電腦上,以上的運算都屬於Arithmatic Logic Unit(ALU),所需運算時間差不多,結論是quickBitcount大約比bitcount快上一倍.
Great!
回覆刪除