位元運算讓我們可以操作二進位數字裡的個別位元。
Elm 在它的 Bitwise 模組 中提供了幾個位元運算子。
修改數字中的個別位元稱為_遮罩_。
_遮罩_是一個數字,其中特定的位元以特定方式設定,讓我們能用 and、or 和 xor 等位元運算子來操作另一個數字。
and 會把兩個數字合併,只保留在兩個數字中都是 1 的位元。
這在檢查某個位元是否被設定時很有用。
舉例來說,要檢查某個數字的第 4 個位元是否設為 1,可以把它和遮罩 01000(十進位的 8)做 and,然後看看結果是不是非零:
Bitwise.and 13 8 --> 8
-- 13 = 01101
-- 8 = 01000
-- and = 01000 = 8
or 會把兩個數字合併,只要某個位元在其中一個或兩個數字中是 1,就把結果的該位元設為 1。
這在把某個特定位元設為 1 時很有用。
舉例來說,要把 10101 的第 2 個位元設為 1,可以把它和遮罩 00010 做 or:
Bitwise.or 21 2 --> 23
-- 21 = 10101
-- 2 = 00010
-- or = 10111 = 23
xor 會把兩個數字合併,如果某個位元在一個數字中是 1、在另一個數字中是 0,就把結果的該位元設為 1。
這在把某個位元翻轉成相反值時很有用:
Bitwise.xor 20 5 --> 17
-- 20 = 10100
-- 5 = 00101
-- xor = 10001 = 17
complement 會反轉數字中的每個位元(0 變成 1,1 變成 0)。
要注意,這會讓正數變成負數,負數變成正數。
這是因為二進位中的負數是以最左邊的位元為 1 來表示。
Bitwise.complement 21 --> -22
-- 21 = 00000000000000000000000000010101
-- complement = 11111111111111111111111111101010 = -22
以下運算子會把位元向左或向右移動指定的位置數量,效果等同於乘以或除以 2 的次方。
shiftLeftBy 會把位元向左移,並從右側補 0。
舉例來說,把 21 向左移 3 個位置:
Bitwise.shiftLeftBy 3 21 --> 168
-- 21 = 10101
-- shiftLeftBy 3 = 10101000 = 168
這等同於 21 * 2^3 = 21 * 2 * 2 * 2 = 168。
shiftRightBy:把位元向右移:
Bitwise.shiftRightBy 2 21 --> 5
-- 21 = 10101
-- shiftRightBy 2 = 00101 = 5
向右移 2 個位置等同於整數除以 4。
要注意,這個函式會複製最左邊位元的值。 因此,負數會維持負數:
Bitwise.shiftRightBy 3 -21 --> -3
-- -21 = 111...101011
-- shiftRightBy 3 = 111...11101 = -3
如果你想向右移位並補零,可以使用 shiftRightZfBy:
Bitwise.shiftRightZfBy 3 -21 --> 536870909
-- -21 = 111...101011
-- shiftRightZfBy 3 = 00111...11101 = 536870909
你的朋友剛傳來一則訊息,裡頭有個重要的秘密。 他不想讓別人輕易讀懂,所以把訊息經過一連串的位元操作加密了。 你需要撰寫幾個函式來協助解密這則訊息。
解密訊息的第一步,是把加密時位移過的位元往右移回來。
解密過程後續的步驟會假設左側補進的是 0。
實作 shiftBack 函式,它接收要位移的位數和一個值,並執行位移。
shiftBack 2 42 --> 10
接下來,有些位元需要設成 1。
實作 setBits 函式,它接收一個遮罩和一個值,並把值中的位元設為 1。
當遮罩中的某個位元是 1 時,值中對應的位元也應該設為 1。
其他所有位元則保持不變。
setBits 66 212 --> 64
加密過程中有些位元被翻轉了。 要解密訊息,就得把它們翻轉回來。
實作 flipBits 函式,它接收一個遮罩和一個值。
遮罩指出值中哪些位元要翻轉。
如果遮罩中的位元是 1,就把值中對應的位元翻轉。
其他所有位元則保持不變。
flipBits 23 157 --> 138
另外還有一些位元,解密後一定是 0。
實作 clearBits 函式,它接收遮罩和值。
當遮罩中的位元是 1 時,value 中對應的位元應該設為 0。
其他所有位元則保持不變。
clearBits 2 15 --> 13
現在你已經有需要的所有函式,可以解碼朋友傳來的訊息了。
實作 decrypt 函式,依序執行下列操作:
decrypt 380182 --> 11840
請用你在前面幾個任務中實作的函式來完成 decrypt。