來談談C++ 位運算 & | > ^ ~ %
老實說,我對+ = * / % && || ==一些比較簡單的運算子比較熟悉。對位運算就陌生了,主要用的少。我覺得高手用的會比較多,因為位運算速度比較快。
1.&
如果兩個相應的二進位制位都為1,則該位的結果值為1;否則為0。
注:下面都用8位的 unsigned char 來做例子。&簡單舉例:
11&3 = 3
00001011
& 00000011
= 00000011 = 3
&比較實用的例子:
比如我們經常要用的是否被2整除,一般都寫成 if(n % 2 == 0)
可以換成 if((n&1) == 0)
2. |
如果兩個相應的二進位制位只要有一個是1,結果就是1;否則為0。
| 簡單例子:
11 | 3 = 11
00001011
| 00000011
= 00001011 = 11| 比較實用的例子
可以用一個unsigned int 來儲存多個布林值。比如一個檔案有讀許可權,寫許可權,執行許可權。看起來要記錄3個布林值。我們可以用一個unsigned int也可以完成任務。
一個數r來表示讀許可權,它只更改個位來記錄讀許可權的布林值
00000001 (表示有讀許可權)
00000000 (表示沒有讀許可權)
一個數w表示寫許可權,它只用二進位制的倒數第二位來記錄布林值
00000010 (表示有寫許可權)
00000000 (表示沒有寫許可權)
一個數x表示執行許可權,它只用倒數第三位來記錄布林值
00000100 (表示有執行許可權)
00000000 (表示沒有執行許可權)
那麼一個檔案同時沒有3種許可權就是
~r | ~ w | ~ x 即為 00000000,就是0
只有讀的許可權就是
r | ~w | ~x 即為 00000001,就是1
只有寫的許可權就是
~r | w | ~x 即為 00000010,就是2
...
一個檔案同時有3種許可權就是
r | w | x 即為 00000111,就是7
3. << 向左移位移
<<簡單例子(向左移一位,右邊自動補0)
11 << 1 = 22
00001011 << 1
00010110 = 22
相當於二進位制的每個數都變成當前值的兩倍,結果就是變成當前值的兩倍。
n * 2 == (n << 1)
推廣下就是(注意可能會溢位)
4. >> 向右位移
>>簡單例子(向右移一位,左邊自動補1)
11 >> 1 = 5
00001011 >> 1
00000101 = 5
注意到最後一位的1被幹掉了。
比較實用的例子是:
int n = n / 2 等價於 int n = n >> 1 等價於 int n >>= 1
5. ^ 異或
兩個相同的數會變成0,反之是1
例子:
11^3 = 8
00001011
^ 00000011
= 00001000 = 8我覺得理解異或,一定要用異或來解下面的題目:
Given an array of integers, every element appearstwice except for one. Find that single one.
就是一個數組中,所有數字都出現了兩次,只有一個沒有
比如 int t = {1,2,3,3,2,1,5} 要找到5。
用異或就完美了,所有相同的都會消失,留下來的就是5了。我發現異或是嫉妒成雙成對的。
int singleNumber(int A[], int n) {
for(int i = 1; i < n; ++i){
A[0] ^= A[i];
}
return A[0];
}
還有就是用不tmp值來交換兩個數
//不用temp交換兩個整數
void swap(int& x , int& y)
{
x ^= y;
y ^= x;
x ^= y;
}
扯點別的,^在lua中表示pow的意思,這是要逆天。
6 ~
這個在加法中用到
x-y = x + ~y + 1
所以~y = - y -1
比如 ~11 = -11 -1 = -12
7 再扯下%
居然有道題目是這樣的: 求 100 % 8的 優化解法。我們知道:
8剛好是2的3次方
所以 100 % 8 == 100 - math.floor(100 / 8) * 8 == 100 - ((100 >> 3) << 3)
8.位運算優先順序
總的來說比較低,一定要加括號。