程序中的全部數在計算機內存中都是以二進制的形式儲存的。位運算說穿了,就是直接對整數在內存中的二進制位進行操做。html
0表示False,1表示True,空位都當0處理算法
含義 | Pascal語言 | C語言 | Java |
---|---|---|---|
按位與 | a and b | a & b | a & b |
按位或 | a or b | a | b | a | b |
按位異或 | a xor b | a ^ b | a ^ b |
按位取反 | not a | ~a | ~a |
按位左移 | a shl b | a << b | a << b |
無符號右移 | a shr b | a >> b | a >> b |
帶符號右移 | a>>> b |
注意C中的邏輯運算和位運算符號是不一樣的。520|1314=1834,但520||1314=1,由於邏輯運算時520和1314都至關於True。一樣的,!a和~a也是有區別的。數據結構
=== 1. and運算 ===加密
and運算一般用於二進制取位操做,例如一個數 and 1的結果就是取二進制的最末位。這能夠用來判斷一個整數的奇偶,二進制的最末位爲0表示該數爲偶數,最末位爲1表示該數爲奇數。spa
相同位的兩個數字都爲1,則爲1;如有一個不爲1,則爲0。htm
00101對象
11100排序
(&;或者and)內存
----------------get
00100
=== 2. or運算 ===
or運算一般用於二進制特定位上的無條件賦值,例如一個數or 1的結果就是把二進制最末位強行變成1。若是須要把二進制最末位變成0,對這個數or 1以後再減一就能夠了,其實際意義就是把這個數強行變成最接近的偶數。
相同位只要一個爲1即爲1。
00101
11100
(|或者or)
----------------
11101
=== 3. xor運算 ===
異或的符號是⊕。按位異或運算, 對等長二進制模式按位或二進制數的每一位執行邏輯按位異或操做. 操做的結果是若是某位不一樣則該位爲1, 不然該位爲0.
xor運算的逆運算是它自己,也就是說兩次異或同一個數最後結果不變,即(a xor b) xor b = a。xor運算能夠用於簡單的加密,好比我想對我MM說1314520,但怕別人知道,因而雙方約定拿個人生日19880516做爲密鑰。1314520 xor 19880516 = 20665500,我就把20665500告訴MM。MM再次計算20665500 xor 19880516的值,獲得1314520,因而她就明白了個人企圖。
相同位不一樣則爲1,相同則爲0。
00101
11100
(^或者xor)
----------------
11001
運算結果
x <- x # y
y <- x @ y
x <- x @ y
執行了第一句後x變成了x # y。那麼第二句實質就是y <- x # y @ y,因爲#和@互爲逆運算,那麼此時的y變成了原來的x。第三句中x實際上被賦值爲(x # y) @ x,若是#運算具備交換律,那麼賦值後x就變成最初的y了。這三句話的結果是,x和y的位置互換了。
加法和減法互爲逆運算,而且加法知足交換律。把#換成+,把@換成-,咱們能夠寫出一個不須要臨時變量的swap過程(Pascal)。
procedure swap(var a,b:longint);
begin
a:=a + b;
b:=a - b;
a:=a - b;
end;
好了,剛纔不是說xor的逆運算是它自己嗎?因而咱們就有了一個看起來很是詭異的swap過程:
procedure swap(var a,b:longint);
begin
a:=a xor b;
b:=a xor b;
a:=a xor b;
end;
注意:位運算版本的交換兩數不適用於一個數的自我交換。也就是說,若是上述程序的"b"改爲"a"的話,其結果是變量a變成零。所以,在使用快速排序時,因爲涉及到一個數的自我交換,所以若是要在其中使用位運算版的交換兩數的話,應該先判斷。具體的時間損耗在此略過。
=== 4. not運算 ===
not運算的定義是把內存中的0和1所有取反。使用not運算時要格外當心,你須要注意整數類型有沒有符號。若是not的對象是無符號整數(不能表示負數),那麼獲得的值就是它與該類型上界的差,由於無符號類型的數是用00到$FFFF依次表示的。下面的兩個程序(僅語言不一樣)均返回65435。
var
a:word;
begin
a:=100;
a:=not a;
writeln(a);
end.
若是not的對象是有符號的整數,狀況就不同了,稍後咱們會在"整數類型的儲存"小節中提到。
=== 5. shl運算 ===
a shl b就表示把a轉爲二進制後左移b位(在後面添b個0)。例如100的二進制爲1100100,而110010000轉成十進制是400,那麼100 shl 2 = 400。能夠看出,a shl b的值實際上就是a乘以2的b次方,由於在二進制數後添一個0就至關於該數乘以2。
一般認爲a shl 1比a * 2更快,由於前者是更底層一些的操做。所以程序中乘以2的操做請儘可能用左移一位來代替。
定義一些常量可能會用到shl運算。你能夠方便地用1 shl 16 - 1來表示65535。不少算法和數據結構要求數據規模必須是2的冪,此時能夠用shl來定義Max_N等常量。
=== 6. shr運算 ===
和shl類似,a shr b表示二進制右移b位(去掉末b位),至關於a除以2的b次方(取整)。咱們也常常用shr 1來代替div 2,好比二分查找、堆的插入操做等等。想辦法用shr代替除法運算可使程序效率大大提升。最大公約數的二進制算法用除以2操做來代替慢得出奇的mod運算,效率能夠提升60%。
C語言中位運算符之間,按優先級順序排列爲
1 |
~ |
2 |
<<、>> |
3 |
& |
4 |
^ |
5 |
| |
6 |
&=、^=、|=、<<=、>>= |