神奇的位運算 bitwise trick

2021-07-03 13:12:25 字數 3390 閱讀 5769

在計算機中,資料都以二進位制補碼的形式儲存,根據這一特點,適當採用位運算(bitwise operation)可以很巧妙地解決問題,同時運算效率更高。時刻牢記,最大的負數是-1,在計算機中,它的儲存形式是全1。

左移相當於乘以2,友誼相當於除以2.在計算機中,位運算比乘法、除法運算要快得多,所以適當採用移位運算取代乘除運算,能夠提高運算效率。右移時要注意符號位的擴充套件。

&運算的特點是可以將某些位置為0。

&運算也可用於提取某些特定的位。做法是定義乙個mask,mask中對應要提取的位置為1,而其它位為0,將整數與mask做&運算,就可以提取出整數中相應的位。

|運算的特點是,可以將指定的位元置為1。

以下運算的規律在解決問題時可能是會經常用到的。

x^x=0

bit^1=~bit x^(-1)=~x

bit^0=bit x^0=x

~運算的特點是將0和1點到。以下規律值得牢記,此規律對正整數或負整數都成立。

-x=~x+1

位運算結合在一起,惡意巧妙地解決很多問題,下面就是一些bitwise trick

void swap(int &x, int &y)

最早以前,我所知道的交換方法是下面這樣的

void swap(int &x,int &y)

這樣在大多數情況下也是可以的,但是不及位運算。首先,撇開運算速度不說,通過加減交換最大的隱患在於,如果x和y的值都很大,那麼在計算x+y的時候,可能發生溢位,這在位運算中是絕對不會出現的。

void powerof2(int x)

x&(x-1)的作用是,使得x最右邊的1變為0,x是2的冪,意味著x中只有乙個1,所以經過這一運算後,x&(x-1)等於0。

還有乙個特點需要注意的是,如果x是2的冪,那麼x-1的形式是,左邊全為0,右邊全為1。

另乙個解為return x&(-x) ==x;,但是具體怎麼解,我還不明所以。

x&(x-1)的作用不容小覷,我們可以用它來計算整數中1的個數,並藉此來對整數做奇偶校驗。

int countof1(int x)

return

count;

}

int diffmn(int m,int n)

return

count;

}

int plus1(int x)

int minus1(int x)

注意:通過上述方法計算整數的加1或減1,比直接計算是要慢的。不過,這兩個例子充分說明了位運算可以做的事情是很多的。

老實說,這兩個結果應該不是那麼容易記清的吧,起碼對我來說是這樣的,牢記-x=~x+1,並記住大概的形式,應該就能夠通過簡單的變換很快得出正確的結果的吧。

void revsign(int x)

void revsign(int x)

顯然,第二種方法是不如第一種方法的,還是那句話,通過推導,好好體會一下位運算的神奇效果吧。

bool isodd(int x)

偶數的判斷當然也很簡單了!

int

abs(int x)

首先需要注意的是右移時會擴充套件符號位。如果x是正數,那麼x>>31=0,毫無疑問,return語句中的表示式結果就是x;如果x是負數,那麼x>>31的結果就是全1,也就是我們必須牢記的-1,於是

(x^(x>>31)) - (x>>31)

=(x^(-1)) - (-1)

=~x + 1

=-x

所以,(x^(x>>31))-(x>>31)就是我們要求的x的絕對值。

int

max(int a,int b)

對於unsigned int,右移31位是乙個很特別的操作,其作用是將所有的位都置為符號位的值,也就是說,正數移位後變為0,負數移位後變為-1。所以,如果a>31結果就是-1,而~(a-b)>>31結果就是0,最終maxab = b;反過來,如果a>b,那麼(a-b)>>31結果是0,而~(a-b)>>31結果是-1,最終maxab = a

需要注意的是,此處假定在32位機器上進行操作,因此移位的位數是31,為了保證表示式的通用性,可以通過sizeof(int)*8 - 1來確定移位的位數。

下面是另外一種解法,成立的條件是true=1,false=0

int

max(int a,int b)

如果ab,那麼-(a可以看到,兩種解法的核心都是將a、b的關係通過-1或0來間接表示,並利用表示結果作進一步的運算。

int

min(int a,int b)

同樣的,只要滿足true=1,false=0,也同樣可以採用第二種方法來求最小值。

int

min(int a)

推導過程與注意事項同求最大值的解法是基本相同的,在此不做贅述。

int mean(int x,int y)

我們知道,計算兩個數的平均值,最直接的想法就是(x+y)/2,表示式就是通過位運算實現了這一想法。表示式的核心思想是,將x+y分解成兩部分,一部分是x和y相同的位,一部分是x和y不同的位,前者通過&運算完成相加(由於沒有進製,所以無需除以2),後者通過^運算完成相加,然後除以2得出平均值,最後,將兩部分相加,就是所求的結果了。

同樣的,通過位運算,可以成功規避相加溢位的問題。

在此,我們瞥見了位運算的一抹影子,你當然可以在其他很多地方領略到更多神奇之處,比如在演演算法筆記中。

位運算的神奇用法

按位與如果兩個相應的二進位制位都為1,則該位的結果值為1,否則為0 按位或兩個相應的二進位制位中只要有乙個為1,該位的結果值為1 按位異或 若參加運算的兩個二進位制位值相同則為0,否則為1 取反 是一元運算子,用來對乙個二進位制數按位取反,即將0變1,將1 左移用來將乙個數的各二進位制位全部左移n位...

神奇的按位運算 python

先來看leetcode 29上的divide two integers題目要求 divide two integers without using multiplication,division and mod operator.if it is overflow,return max int.就是...

攔截飛彈 加了神奇的位運算

傳送門 洛谷 p1020 飛彈攔截 思路 第一問為求一段序列 的最長不下降子串行的長度 第二問求得是 不下降子串行的個數 對於第一問,跑一邊 最長不下降子串行即可 對於第二問,依舊是跑一邊第一問即可 霧 其實還要加一點神奇的位運算。include include include define max...