阅读 csapp v3 时,练习题 2.13 很有意思。练习题描述如下。
位设置是对于参数 mask 中每一个为 1 的位,那么参数 x 中相应位则被设置为 1 ;位清除是对于参数 mask 中每一个为 1 的位,那么参数 x 中相应位则被设置为 0 。假设有两个函数 bis 和 bic 来实现位设置和位清除,请使用这两个函数实现两个数的异或结果。
小提示:可以使用的位运算是与、或和非。
local function bis(x, mask)
return x | mask
end
local function bic(x, mask)
return x & ~mask
end
什么是异或呢?异或就是两个值中,至少有一个为真,但不全为真,那么结果就是真,否则结果就是假。对于两个二进制位,至少有一个位为 1 但不全为 1,那么结果就是 1,否则结果是 0 。
也就是说只有 (1 异或 0) 或者 (0 异或 1) 结果才为 1,其余结果都为 0 。只要两个位不相同,那么结果就是 1 。所以问题变成了如何判断两个位不同。
与运算要求两个位都是 1 时,结果才是 1,因此 1 & ~0
结果是 1 而 ~0 & 1
结果也是 1,这做实现了两个位不同,而结果是 1 。由于存在 1 & ~0
或 ~0 & 1
,因此异或运算可被拆分为 (1 & ~0) | (~0 & 1)
。推广成 (x & ~y) | (~x & y)
。
经过分析后,发现完全可以代入上面的函数。于是实现异或的代码如下。
local function exor(x, y)
return bis(bic(x, y), bic(y, x))
end
完整的测试用例 Lua 代码如下。
local function bis(x, mask)
return x | mask
end
local function bic(x, mask)
return x & ~mask
end
local function exor(x, y)
return bis(bic(x, y), bic(y, x))
end
local x, y = 0x12345678, 0x87654321
assert(exor(x, y) == x ~ y
参考内容
- 深入理解计算机操作系统 - 习题 2.13