1.判斷奇偶
只要根據最未位是0還是1來決定,爲0就是偶數,爲1就是奇數。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)來判斷a是不是偶數。
2.交換兩數
可以用位操作來實現交換兩數而不用第三方變量:
void Swap(int &a, int &b)
{
if (a != b)
{
a ^= b;
b ^= a;
a ^= b;
}
}
第一步 a^=b 即a=(a^b);
第二步 b^=a 即b=b^(a^b),由於^運算滿足交換律,b^(a^b)=b^b^a。由於一個數和自己異或的結果爲0並且任何數與0異或都會不變的,所以此時b被賦上了a的值。
第三步 a^=b 就是a=a^b,由於前面二步可知a=(a^b),b=a,所以a=a^b即a=(a^b)^a。故a會被賦上b的值。
再來個實例說明下以加深印象。int a = 13, b = 6;
a的二進制爲 13=8+4+1=1101(二進制)
b的二進制爲 6=4+2=110(二進制)
第一步 a^=b a = 1101 ^ 110 = 1011;
第二步 b^=a b = 110 ^ 1011 = 1101;即b=13
第三步 a^=b a = 1011 ^ 1101 = 110;即a=6
3.變換符號
變換符號就是正數變成負數,負數變成正數。
如對於-11和11,可以通過下面的變換方法將-11變成11
1111 0101(二進制) –取反-> 0000 1010(二進制) –加1-> 0000 1011(二進制)
同樣可以這樣的將11變成-11
0000 1011(二進制) –取反-> 0000 0100(二進制) –加1-> 1111 0101(二進制)
4.求絕對值
位操作也可以用來求絕對值,對於負數可以通過對其取反後加1來得到正數。對-6可以這樣:
1111 1010(二進制) –取反->0000 0101(二進制) -加1-> 0000 0110(二進制)
來得到6。
因此先移位來取符號位,int i = a >> 31;要注意如果a爲正數,i等於0,爲負數,i等於-1。然後對i進行判斷——如果i等於0,直接返回。否之,返回~a+1。int my_abs(int a)
{
int i = a >> 31;
return i == 0 ? a : (~a + 1);
}
現在再分析下。對於任何數,與0異或都會保持不變,與-1即0xFFFFFFFF異或就相當於取反。因此,a與i異或後再減i(因爲i爲0或-1,所以減i即是要麼加0要麼加1)也可以得到絕對值。所以可以對上面代碼優化下:
int my_abs(int a)
{
int i = a >> 31;
return ((a ^ i) - i);
}
5. 高低位交換
給出一個16位的無符號整數。稱這個二進制數的前8位爲“高位”,後8位爲“低位”。現在寫一程序將它的高低位交換。例如,數34520用二進制表示爲:
10000110 11011000
將它的高低位進行交換,我們得到了一個新的二進制數:
11011000 10000110
它即是十進制的55430。
這個問題用位操作解決起來非常方便,設x=34520=10000110 11011000(二進制) 由於x爲無符號數,右移時會執行邏輯右移即高位補0,因此x右移8位將得到00000000 10000110。而x左移8位將得到11011000 00000000。可以發現只要將x>>8與x<<8這兩個數相或就可以得到11011000 10000110。
6. 缺失的數字
很多成對出現數字保存在磁盤文件中,注意成對的數字不一定是相鄰的,如2, 3, 4, 3, 4, 2……,由於意外有一個數字消失了,如何儘快的找到是哪個數字消失了?
由於有一個數字消失了,那必定有一個數只出現一次而且其它數字都出現了偶數次。用搜索來做就沒必要了,利用異或運算的兩個特性——1.自己與自己異或結果爲0,2.異或滿足交換律。因此我們將這些數字全異或一遍,結果就一定是那個僅出現一個的那個數。