前言
位運算是基於整數的二進制表示進行的運算,即運算時是考慮整數對應的二進制表示,並對二進制每一位所考慮的運算。常用的運算符共 6 種,分別為與(&)、或(|)、異或(^)、取反(~)、左移(<<)、右移(>>)和無符號右移(>>>,只有部分語言才有的特性,比如Java)。其中除了&以外,其它幾個運算符均為二元運算符。
基礎介紹
| 運算符 | 運算規則 |
|---|---|
& |
只有兩個操作數對應位均為1時才為1,否則為0 |
| ` | ` |
^ |
只有兩個操作數對應位不相等時才為1,否則為0 |
~ |
將操作數的二進制表示的每一位取反,即0變1,1變0 |
<< |
將操作數的完整二進制表示,去掉高位,低位補0 |
>> |
將操作數的完整二進制表示,去掉低位,若操作數為正數,則高位補0,為負,則補1 |
>>> |
將操作數的完整二進制表示,去掉低位,不管操作數為正還是為負,均補0 |
特別注意
當進行位移運算時,右操作數位移不應該超過整數的最大位數,當然超過了也不會報錯,但不同語言的處理細節有所不同,大家如果感興趣可以看下《深入理解計算機系統》,里面有具體的介紹。
基礎使用
為了運算方便,這里假設每個數都只有4位,半個字節,故只能表示-8 ~ 7,下面先展示每個運算符的使用:
-
&的使用對於
2 & 3而言,我們先得到兩個數的二進制完整表示:2(0010), 3(0011),然后按照&的規則進行運算:0 0 1 0
&
0 0 1 1
0 0 1 0 (2)
-
|的使用對於
4 | 1而言,我們同樣先得到兩個數的二進制完整表示:4(0100),1(0001),然后按照|的規則進行運算:0 1 0 0
|
0 0 0 1
0 1 0 1 (5)
-
^的使用對於
6 ^ 2而言,我們還是先得到兩個數的二進制完整表示:6(0110),2(0010),然后按照^的規則進行運算:0 1 1 0
^
0 0 1 0
0 1 0 0 (4)
-
~的使用對於
~3而言,我們依舊還是先得到3的二進制完整表示:3(0011),然后按照~的規則進行運算:~
0 0 1 1
1 1 0 0 (-4,因為我們上文說了假設數字都是只有四位,因此最高位為符號位)
正數對應的二進制表示,我們一般經過稍加計算很快就可以得到,對於負數的二進制,則可以通過負數相反數進行取反加1得到。例如為了得到-7的二進制,我們首先知道7的二進制為
0111,然后先進行取反操作,得到1000,然后再加1,得到1001,即為-7所對應的二進制表示。 -
<<的使用對於
1 << 2而言,我們依然還是先得1的二進制完整表示:1(0001),然后按照<<的規則進行運算:舍去最高的2位得到
01,然后低位補2個0,得到0100,0100(4)即為最終的結果,這里需要注意一點,<<操作並不是完全等同於將左操作數 * 2右操作數,在計算機里,由於位數的限制,可能會出現運算溢出,因此,對於1 << 3,按照上述規則得到1000,由於最高位為符號位,因此得到的結果不是8,而是-8,甚至對於1 << 4, 按照上述規則會得到0000,即在這里1 << 4的結果為0,而非16(正常不應該讓位移數操作整數的最大位數,這里僅作講解使用),大家想要驗證的話,可以測試0x4000 0000 << 1和0x 4000 0000 << 2(注意這里是16進制的表示形式,轉換為二進制表示的話,需要將每一位轉換為對應的4位二進制數)即可。 -
>>的使用由於
>>為有符號右移,所以這里展示兩個例子先說6 >> 2,我們先得到6的二進制數表示:6(0110),然后按照>>的規則進行運算:首先舍去低2位,得到01,由於為正(最高符號為為0),因此高位需要補2個0,得到0001(1),即為最終的結果。然后再說一個負數的例子,對於-7 >> 1,我們先得到-7的二進制完整表示:-7(1001),然后先舍去低1位,得到100,由於為負(最高符號為為1),因此高位需要補1個1,得到1100(-4),即為最終的結果。 -
>>>的使用>>>和>>的唯一區別就是當左操作數為負數的時候,當運算先舍去低位后,高位也同樣補0了,而不是7,還是舉剛才-7 >>> 1的例子,我們先得到-7的二進制完整表示:-7(1001),然后先舍去低1位,得到100,最后我們在高位補0,得到0100,即為最終的結果。如果想自己進行代碼驗證的話,-7的32進制表示為0xffff fff5,舍棄低位,高位補0,會得到0x7fff fffc(2147483644)即為最終的結果。特別注意,不管是
<<、>>還是>>>當位移數為0時,得到的結果都是原數。
小結
以上便是關於位運算的基礎入門知識,后續還會繼續總結位運算的常見技巧以及實際運用等,希望能和大家多多交流,如有錯誤之處,也請幫忙指出。
