很有趣的位移運算子與位元運算

原來寫程式還可以這樣子操作。

位元的概念

首先,電腦是用「位元」來當作單位,也就是二進位的 0 跟 1,所以這裡提的位元,就是指「二進位」數字的意思。

位移運算子

位移運算子是對「位元」來做位移,在效能上會比你直接用加減乘除那些來的好(畢竟電腦的最底層就是一堆 0101),所以這是一個很值得學的東西。

如果忘記二進位怎麼轉換的話先幫你複習一下:

假設有一個數字是 100

用數學來寫的話會是:2^0 x 0 + 2^1 x 0 + 2^2 x 1 = 4

但因為如果是 0 的話就等於 2^n x 0,所以你看的時候可以直接忽略,直接思考「有值的那一個位數」是多少次方就好,這樣比較快:

0100 = 2^2 = 4
1000 = 2^3 = 8
10000 = 2^4 = 16

位移運算的意思是就是「先把這個數字轉換成二進位」,接著把每一位往「左或右」位移,後面補 0:

1
2
4 << 1 
8

上面的過程可以想成是這樣:

1
2
3
4
4 => 0100  轉成二進位
0100 << 1 每一位往左移一位
1000 接著轉回十進位
8

因為在二進位裡,每進一位就代表 x2,所以 4 往左位移一位,就等於 4 x 2,得到 8。

如果 4 往左移兩位,就等於 4 x 2 x 2,得到 16,以此類推。

所以有一個很直覺又簡單的記法:

2 << 1 看成是 2 x 2^1 = 4
2 << 2 看成是 2 x 2^2 = 8
2 << 3 看成是 2 x 2^3 = 16

總而言之,位移幾次 2 就乘幾次,接著在乘上原本的數字,以此類推。

如果是往右移的話就反過來,變成「除法」的意思,每往右移一位,就除以 2 一次,但要注意的是右移運算會省略掉「浮點數」:

1
2
3
4
5
3/2
1.5

3 >> 1
1

位元運算

位元運算子:

  • &(AND)
  • |(OR)
  • ^(XOR)
  • ~(NOT)

位元運算指的就是用「二進位來做運算」,參考這個圖:

bitwise-AND

意思是對 10 跟 15 做 & 位元運算(AND),1 代表 true,0 代表 false。

所以最後的結果是 1010,也就是 10

用 JavaScript 寫的結果:

1
2
10 & 15
10

|(OR)也是一樣的道理:

1
2
10 | 15
15

比較特別的是 XOR 跟 NOT。

^(XOR)是只有在 0110 的時候是 true,其他皆 false:

bitwise-XOR

所以用 JavaScript 寫的結果是:

1
2
10 ^ 15
5

~(NOT)是把每個位元都做反向處理。

不過要注意一下,以剛剛的例子 15(1111) 你可能以為做完會變成 0(0000),但並不是這樣子:

1
2
~15 
-16

這是因為 NOT 是對「所有位元」都做反轉,所以不能只看 1111 這四個位元,因為可能還有其他位元(假設有 32 位元好了)也跟著被反轉,所以最後才會得到 -16

用位元運算來判斷偶數奇數

先思考這張圖的意思:

bitwise-Ex

意思是說我們只想知道最後一個數字是 0 還是 1

這樣子做有什麼用途?仔細想想看,在二進位的世界裡,只有「最後一個位元」能決定一個數字是奇數還是偶數,其他位元只會有可能是 02 的倍數,換句話說就是「其他位元只會產出偶數」。

但是最後一個位元不一樣,他會有 01 這兩個可能。所以重點來了,當結果是 0 的時候,最後的結果一定會是 偶數,因為「偶數 + 偶數」永遠都只會是偶數;反過來,當結果是 1 的時候,最後的結果一定會是 奇數,因為「偶數 + 奇數」永遠都會是奇數。

所以我可以直接驗證:

1
2
3
4
5
10&1
0

11&1
1

用位元運算來當作遮罩

我還不太懂這能怎麼運用,但就先記下來,看以後會不會想到。

簡單來說,前面是用: A & 1 來判斷最後一位數是不是 1

你也可以換個想法,假設我想看第四個位元是不是 1,就可以用 A & 8(8=1000)來做判斷。

0 就代表第四位不是 11 就代表第四位是 1

當位元運算碰到奇怪的資料型態

我做題目時發生的經驗,想留個紀錄。

我在用「變數」來做位元運算時,因為不確定這個變數值都跟我預期中的一樣,所以引發了一些非預期的結果,例如:

1
2
3
4
5
6
7
n = undefined
n = NaN
n = null
n = 'String'
n = false

1 << n

不管 n 的值是哪個,最後的輸出都會是 1,所以在做位元運算時要特別注意「變數值」的是否正確問題,要不然直接帶「數字」來做會比較安全一點。

另外如果 n = true 的情況比較特別一點:

1
2
n = true
1 << n

結果會是 4

這是因為 true 代表 1,所以想成是這樣:

1
2
n = true
1 << 1

甚至要這樣玩也可以:

1
1 << true + true + true 

最後就會輸出 1 << 3 的結果。

位元運算的執行順序

就跟一般的加減乘除一樣,所以不用特別在用括號括起來:

1
2
3
1 >> 2 > 3  // true
1 + 1 > 3 // false
1 ** 2 > 2 //false
從 Object 的等號來真正理解變數 我的第一個 Shell Script
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×