位運算主要知識
阿新 • • 發佈:2019-01-24
什麼是位運算?
程式中的所有數在計算機記憶體中都是以二進位制的形式儲存的。位運算說穿了,就是直接對整數在記憶體中的二進位制位進行操作。C++提供了6種位運算子來進行位運算操作:
& 按位與
| 按位或
^ 按位異或
~ 按位取反
<< 左移(左邊消失,右邊補0)
>> 右移(右邊消失,左邊補符號位)
位運算的運算元是整數型別或字元型.
按位與&運算
將參與運算的兩運算元各自對應的二進位制位進行與操作。例如:6的二進位制是110,11的二進位制是1011,那麼6 & 11的結果就是2110
& 運算常常用來將某變數的某些位清0,而保留其它位不變。例如,需要將int型變數n的低8位全置成0,而其餘位不變,則用:
n = n & 0xFFFFFF00
& 也常用於二進位制取位操作,例如一個數 & 1的結果就是取二進位制的最末位。如果要判斷n的第8位(從右往左,從1開始數)是否是1,則用:
if (n & 0x80 == 0x80) 語句
附註:int型是32個二進位制位,16進位制整數每個數字代表4個二進位制位,故16進位制int型常量最多是8位。
按位或|運算
|運算通常用於二進位制特定位上的強制置1,例如一個數或 1的結果就是把二進位制最末位強行變成1。110 | 1011 ------------ 1111 --> 15
按位異或^運算
0^0=0 0^1=1 1^1=0^運算通常用於對二進位制的特定一位進行取反操作.例如n^0xff就使得n的最後8位取反。
110 ^ 1011 ----------- 1101 --> 13
^運算的特點是:如果a^b==c,則有a^c==b和c^b==a
^可用於簡單加密,參見顧森BLOG。
左移<<運算
a << b就表示把a轉為二進位制後左移b位(在後面添b個0)。例如100的二進位制為1100100,而110010000轉成十進位制是400,那麼100 << 2 = 400。可以看出,a << b的值實際上就是a乘以2的b次方通常認為a << 1比a * 2更快,因為前者是更底層一些的操作。因此程式中乘以2的操作請儘量用左移一位來代替。
定義常量時可以用<<運算。你可以方便地用(1 << 16) - 1來表示65535。很多演算法和資料結構要求資料規模必須是2的冪,此時可以用<<來定義MAXN等常量。
右移>>運算
a >> b表示二進位制右移b位(去掉末b位)。當a是正整數時,a>>b等價於a/(2的b次方)
當a是負整數時,a>>b並不等價與a/(2的b次方),而是等於a/(2的b次方)上取整。
如a=-9
cout<<a/2; //輸出-4.
cout<<(a>>1); //輸出-5.
我們也經常用>> 1來代替div 2,比如二分查詢、堆的插入操作等等。
用>>代替除法運算可以使程式效率大大提高。最大公約數的二進位制演算法用除以2操作來代替慢得出奇的%運算,效率可以提高60%。
二進位制求最大公約數原理。
若a<b gcd(a,b)=gcd(b,a)
若a、b都是偶數,則gcd(a,b)=2*gcd(a/2,b/2)
若a是奇數、b是偶數,則gcd(a,b)=gcd(a,b/2)
若a、b都是奇數,則gcd(a,b)=gcd((a-b)/2,b)
位運算的簡單應用
整數型別的儲存
計算機用0x0000到0x7FFF依次表示0到32767的數,剩下的0x8000到0xFFFF依次表示-32768到-1的數。32位有符號整數的儲存方式也是類似的。稍加註意你會發現,二進位制的第一位是用來表示正負號的,0表示正,1表示負。這裡有一個問題:0本來既不是正數,也不是負數,但它佔用了0x0000的位置,因此有符號的整數類型範圍中正數個數比負數少一個。對一個有符號的數進行~運算後,最高位的變化將導致正負顛倒,並且數的絕對值會差1。也就是說,~ a實際上等於-a-1。這種整數儲存方式叫做“補碼”。換言之,~a+1 = -a,那麼a & -a得到什麼?
得到a的右數第1位為1的數,這個操作可用來列舉a中為1的位,這在位操作中有較多應用。