前言
位運算是基於整數的二進制表示進行的運算,即運算時是考慮整數對應的二進制表示,並對二進制每一位所考慮的運算。常用的運算符共 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時,得到的結果都是原數。
小結
以上便是關於位運算的基礎入門知識,后續還會繼續總結位運算的常見技巧以及實際運用等,希望能和大家多多交流,如有錯誤之處,也請幫忙指出。