位运算允许我们操作二进制数中的单个位。
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。