【這里我們將討論一些位操作技巧,如果使用得當會有助於提高你編出的程序執行速度】
我們編程或多或少會使用到位操作,位操作是編程中處理整型數據高效方法。例如,想要求出一個整數二進制位中值為 1 的個數,簡單的方法是用一個循環,其實我們用一兩個位操作的小技巧就能高效的解決。
假設讀者已經知道整型數據二進制補碼表示方式和位操作的基本方式。
我列出下文中將要使用的位操作標記:
& - bitwise and | - bitwise or ^ - bitwise xor ~ - bitwise not << - bitwise shift left >> - bitwise shift right
本文中使用的數字是8bit無符號整型,二進制補碼表示,用‘x’標記,結果用‘y’表示。數‘x’的每一比特位標記為b7, b6, b5, b4, b3, b3, b2, b1 和 b0。b7 是符號位,權重最大,b0 權重最小。
我們從最簡單的開始逐漸過渡到難的。
技巧1:檢查整數是奇數還是偶數
if ((x & 1) == 0) { // x is even } else { // x is odd }
相信很多人都知道這個方法,只要整數的最后一位比特是 1 ,那它就是奇數,反之就是偶數。即 b0 位要么是 1 要么是 0 ,‘x’和 1 與(&)運算,保留了最 b0 位,如果 b0 是 1 ,‘x’是奇數,如果 b0 位是 0 ,‘x’是偶數。
如果還不是很清楚我們去一個整數,例如43,二進制表示為00101011,注意 b0 位為 1,我們將 43 與 1 做 & 運算:
1 00101011 2& 00000001 (note: 1 is the same as 00000001) 3 -------- 4 00000001
從中看到 & 運算怎樣擦除了高位的 b7 ~ b1 位的數據只保留了 b0 位,結果為 1,因此知道 43 是奇數。
技巧2:測試第n位比特
if (x & (1<<n)) { // n-th bit is set } else { // n-th bit is not set }
前面討論過了第一位比特測試,這里做了一些改進,可以測試第任意位比特,只要將與運算的1向左平移相應的位數即可。假設向左平移n位,接下來的與運算就是只保留第n位,其它位都清零了。
下面是簡單的演示:
1 00000001 (same as 1<<0) 1<<1 00000010 1<<2 00000100 1<<3 00001000 1<<4 00010000 1<<5 00100000 1<<6 01000000 1<<7 10000000
小例子:
122的第三位比特是1嗎?(從0開始數)可以這樣做:
122 & (1<<3)
122的二進制表示是01111010,(1<<3)即1向左平移3比特00001000。
1 01111010 2& 00001000 3 -------- 4 00001000
我們看到結果不為0,這題的答案是1。
技巧3:將第n位設為1
y = x | (1<<n)
和前面的技巧一樣,只是把與運算(&)換成了或運算(|)。與1進行或運算將參與運算的位置為1,與0進行或運算參與預算的位不變。
看一個例子:
假設我們要將120的第2位比特設為1:
1 01111000 (120 in binary) 2| 00000100 (1<<2) 3 -------- 4 01111100
技巧4:將第n位設為0
y = x & ~(1<<n)
這個方法的關鍵就是~(1<<n),它將第n位設為0,其它位全部為1。看下面:
~1 11111110 (same as ~(1<<0)) ~(1<<1) 11111101 ~(1<<2) 11111011 ~(1<<3) 11110111 ~(1<<4) 11101111 ~(1<<5) 11011111 ~(1<<6) 10111111 ~(1<<7) 01111111
與‘x’與運算的結果是清零了第n位,不管這一位是1還是0,其它位保持不變。
小例子,將127的第4位設為0:
1 01111111 (127 in binary) 2& 11101111 (~(1<<4)) 3 -------- 4 01101111
技巧5:將第n位取反
y = x ^ (1<<n)
這次使用的是異或運算,如果異或運算的兩個操作數相同,運算結果是0,兩個操作數不同,結果是1。怎樣將第n位取反呢?如果第n位比特為1,將它與1進行異或運算結果就是0,如果它是0,那么它與1異或運算的結果就是1。於是這一位就取反了。
小例子,假設要將值01110101的第5位取反:
1 01110101 2^ 00100000 3 -------- 4 01010101
同樣的數,第5位是0結果如下:
1 01010101 2^ 00100000 3 -------- 4 01110101
注意到沒?對一個數進行兩次同樣的異或運算后結果還是原來的數,這個漂亮的特性可以用在許多編程問題中。