BIS, BIC位运算与逻辑运算的关系

今天读CSAPP, 看到一道题, 蛮有意思的.

题中提到. 在上世纪后期非常流行的 Digital EquipmentVAX 计算机. 它没有布尔运算 ANDOR, 只有bis(位设置)bic(位清除) 两种指令.

这两种指令都接受两个参数, 数据字X掩码字M.

bis 代表将掩码字M中, 每一个为 1 的位置, 其在数据字X上对应位置设置为 1.

例如 X: 11000011, M: 10101010. 因为M中1, 3, 5, 7位置上为1, 所以将X, 1, 3, 5, 7位置设置为1. 结果为11101011

bic 代表 将掩码字M中, 每一个为 1 的位置, 其在数据字X上对应位置设置为 0.

bicbis 语义相反.

我们现在假设我们使用着 VAX, 正要考虑如何用这两个原语实现逻辑操作 OR, AND, XOR.

int bis(int x, int m);
int bic(int x, int m);

先考虑OR

bis 是将所有为1的位置, 都强制写为1, 和当前值为0或1没有任何关系.
也就是当n表示一个位置, (Mn=1) bis (Xn=0/1) = 1 得出 1 bis 0 = 11 bis 1 = 1 . 这和 OR 的特点完全一致.

int bool_or(int x, int y) {
    return bis(x,y);
}

其次是AND

bis1 bis 0/1 = 1 并不能解释 AND , 当已知一边为1时, AND 的结果仍无法确定. 但我们知道, ANDOR 是相反的, OR 是当两边都为0时,结果才为0, 而 AND 是当两边都为1时, 结果全为1.
我们可以得出, 0在 AND 是起绝对作用的. 当一边为0时, 结果一定为0.
那么, 如果构建出 "当一边为0时, 结果一定为0" ?

我们拿一个掩码举例, 例如 10101010, 它作用的位置是1, 3, 5, 7号位. 因为bis和bic都是通过1的位置来操作数据. 那么如何操作0的位置? 也就是说, 如何让bis和bic操作2, 4, 6, 8这四个位置, 因为这里有我们非常重要的 "0".
好, 现在说了这么多, 思路可能有点乱, 让我们理清下现有的内容.

bis 会将掩码中 1 所在的位置, 将数据同样位置强制设置为 1 .
bic 会将掩码中 1 所在的位置, 将数据同样位置强制设置为 0 .
and 操作期待将掩码中 0 所在的位置, 将数据同样位置强制设置为 0

那么bic(X, 0b10101010)是将1, 3, 5, 7 位置设置为0
AND(X, 0b10101010)理应将2, 4, 6, 8位置设置为0;

那么.....答案显而易见了.

int bool_and(int x, int y) {
    return bic(x, ~y);
}

再然后是XOR

XOR比较容易, 因为存在等式, xor = (a & ~b) | (~a & b)

int bool_xor(int x, int y) {
    return bool_or(bool_and(x, ~y), bool_and(y, ~x));
}

我们将其替换一下

int bool_xor(int x, int y) {
    return bis(bic(x, ~~y), bic(y, ~~x));
}

最终版

int bool_xor(int x, int y) {
    return bis(bic(x, y), bic(y, x));
}

我们现在来用C模拟下这两个原语, 因为我们现代的机器不是VAX, 所以仅仅是 模拟. 其实就是上述的逆操作

int bis(int x, int m) {
    return x | m;
}
int bic(int x, int m) {
    return x & ~m;
}

你可能感兴趣的:(BIS, BIC位运算与逻辑运算的关系)