秘密

秘密

学习练习

简介

Crystal 提供了位运算符,可以在二进制层面操作Int。

移位运算符

Crystal 提供了移位运算符,可以把二进制位向左(<<)或向右(>>)移动。

左移(<<)

左移运算符(<<)把二进制位向左移动。 要移动的值写在左边,移动的位数写在右边。

0b0010 << 1
# => 0b0100

0b0010 << 2
# => 0b1000

如果这个数字是负数,那么实际上会向右移动。

0b0010 << -1
# => 0b0001

右移(>>)

右移运算符(>>)把二进制位向右移动。 和左移运算符一样,要移动的值写在左边,移动的位数写在右边。

0b0100 >> 1
# => 0b0010

0b0100 >> 2
# => 0b0001

同样地,如果这个数字是负数,运算符会改为向左移动。

0b0100 >> -1
# => 0b1000

二元运算符

Crystal 有 3 个用于进行位运算的二元运算符(&、|、^),以及一个~运算符。

按位与(&)

二元与运算符(&)对两个值执行按位与运算。 它会把第一个值中的每一位与第二个值中相同位置的位进行比较。 如果两个位都是 1,结果位就设为 1。 否则设为 0。

0b0011 & 0b1010
# => 0b0010

按位或(|)

二元或运算符(|)对两个值执行按位或运算。 它同样会把第一个值中的每一位与第二个值中相同位置的位进行比较。 只要其中任意一位是 1,结果位就设为 1。 否则设为 0。

0b0011 | 0b1010
# => 0b1011

按位异或(^)

二元异或运算符(^)执行按位异或运算。 和按位与、按位或运算符一样,它会把第一个值中的每一位与第二个值中相同位置的位进行比较。 如果其中_只有一位_是 1,结果位就是 1。 否则为 0。

0b0011 ^ 0b1010
# => 0b1001

按位非(~)

最后,按位非运算符(~)会把值中的每一位取反。 与其他二元运算符不同,这是一个一元运算符,只对它右边的值进行操作。

~0b1110_0010
# => 0b0001_1101

说明

你的朋友刚刚给你发来一条消息,里面有一个重要的秘密。 为了不让别人轻易读到它,这条消息通过一系列位操作进行了加密。 你需要写一个程序来帮忙解密这条消息。

1. 将位移回去

解密消息的第一步,是撤销加密过程中的移位:把位再向左移回去。 不同消息需要移动的位数可能不一样。

实现方法Secrets.shift_back,它接收一个值和要向左移动的位数。

Secrets.shift_back(0b0001, 2)
# => 0b0100

2. 应用位掩码

下一步是应用一个位掩码,提取某些位的值。 应用掩码的方式,是对值和掩码执行按位与。

实现方法Secrets.apply_mask,它接收一个值并应用一个掩码。

Secrets.apply_mask(0b0110, 0b0101)
# => 0b0100

3. 设置某些位

向左移位会新添一些 0 位。 其中一些新位需要被设为 1。 按位或可以把某些位设为 1,同时保留其余位不变。

实现方法Secrets.set_bits,它接收两个值并执行按位或。

Secrets.set_bits(0b0110, 0b0101)
# => 0b111

4. 反转异或

加密过程中的一部分,是把数据和约定的值做异或。 要还原成原始值,只需把加密后的值再和约定的值做一次异或即可。 不过,因为一场误会,你的朋友在做异或之前,先把约定值的各位翻转了(也就是对约定值做了按位取反)。

实现Secrets.reverse_xor方法,它接收加密值和约定值,并算出原始值。

Secrets.reverse_xor(0b1100, 0b0101)
# => 0b(0110)
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Crystal Exercism

准备好开始 秘密 了吗?

注册 Exercism,借助 26 个概念142 个练习 和真人导师指导,学习并掌握 Crystal,全部免费。