原题:
Write a function that add two numbers A and B. You should not use +
or any arithmetic operators.
给出两个整数a和b, 求他们的和, 但不能使用 +
等数学运算符。
(错误)解法1:
int aplusb(int a, int b) { // a and b are 32-bit integers
int c = a | b, d = a & b;
return c + d;
}
思路:
- 把输入的两个int看成32位2进制数,则每一位两数全1的时候会发生进位,其他情况不会。
- 两数同一位全1的位可以通过与运算计算得出(‘&’运算结果为1的位即所求);其他情况的位的加法结果和或(‘|’)运算结果相同。
- 而两数同一位全1的时候或运算结果为1,和与运算结果相加,刚好进位,与实际求和结果效果相同
问题:虽然结果正确,但是函数体内仍然使用了‘+’,不符合要求。
解法2:
(递归-1)
int aplusb(int a, int b) { // recursive solution
int xor_r = a ^ b;
int and_r = a & b;
if(and_r == 0) return xor_r;
and_r = and_r << 1;
return aplusb(xor_r, and_r);
}
(递归-2)
int aplusb(int a, int b) { // recursive solution
if (b == 0) return a;
int xor_r = a ^ b;
int carry_r = (a & b) << 1;
return aplusb(xor_r, carry_r);
}
(迭代)
int aplusb(int a, int b) { // iterative solution
int xor_r = a ^ b;
int carry_r = (a & b) << 1;
while (carry_r){
int pre_xor = xor_r;
xor_r = xor_r ^ carry_r;
carry_r = (pre_xor & carry_r) << 1;
}
return xor_r;
}
思路:
同样是借助位运算,而且把两个加数转换成二进制数。
- 此处使用了异或运算 ('^')。由定义可知,‘^’运算结果为1的位加法结果也应为1,而‘^’运算结果为0的值有两种情况:两数同一位全0或者全1。两数同一位全0,结果自然是0 (和异或结果一致),全1时需要“特别处理”。
- 同上一解法,与运算的结果为1的位,两数在此位全1,需要进位(1 + 1 = 10)。 所以可以直接对‘&’运算的结果作左移运算(“<<”),使之进位。
- 所以若将左移的‘&’运算结果和‘^’运算结果相加,可得正确加法结果。
- 然而根据要求,我们不能直接求和,所以问题转换为 对“左移的‘&’运算结果”和“‘^’运算结果”两个新的加数求和。
- 此时可以重复1-4步(实现可用递归或迭代),直到不需要“特别处理”为止,即不再有进位。可知此时‘&’运算结果为0,而‘^’运算结果即所求。
附:
异或运算定义:a⊕b = (¬a ∧ b) ∨ (a ∧¬b), 即a、b不相等时为1,相等时为0.