题意
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
解题思路
本题考察对位运算的灵活使用,即使用位运算实现加法。
加法公式
本位/进位的操作刚好对应二进制操作 异或 与
符号 | 描述 | 运算规则 |
^ | 异或 | 两位不相同,结果为1 |
& | 与 | 两位都为1,结果为1 |
这样我们通过 异或 与
操作就完成了加法计算的 一半 (也叫半加器)。
因为 异或 与
只计算了一半,它只能计算 一位 ;要计算第二位,就要考虑来自低位的进位!所以一个完整的 加法计算 不只有本位的2个 输入 ,还需要来自低位的 进位。这样就是一个完整的 加法计算 (也叫全加器)。
一个全加器可以计算一个位的加法,多个全加器组合,把低位的进位输出,作为高位的进位输入。
本位/进位处理(十进制)
22 + 89 = 111
百 十 个
2 2
+ 8 9
------
0 1 // 本位
1 1 // 进位
01 是计算后的本位,直接记录。11 是计算后的进位,需要:做 进位逻辑 后进入下轮计算。
什么是进位逻辑? —> 乘以进制数,也就是 11 * 10
而这里没有下轮计算了,最终得到 111:
0 1
+ 1 1 0
--------
1 1 1
同样的逻辑在 二进制 里应用:
a ^ b // 计算出2个加数的二进制下,每一位的本位
a & b // 计算出2个加数的二进制下,每一位的进位
(unsigned)(a & b) << 1 // 进位,做进位逻辑,也就是 * 2
//c++不支持负值左移,需要强制转换为无符号数。进位不存在 负 的情况,所以 unsigned 是修饰 进位
算法流程:
(和 s )=(非进位和 n )+(进位 c )。即可将 s = a + b 转化为:s=a+b⇒s=n+c
循环求 n 和 c ,直至进位 c = 0 ;此时 s = n,返回 n 即可。
多想想就明白了,用十进制模拟:比如 12+8,个位的本位是0,进位是1;然后个位的进位要乘10,再和十位相加,然后十位的本位为2,进位为0,循环结束。最终的答案就是各个位数(个位、十位)上的本位组合,即20。
C++实现
class Solution
{
public:
int add(int a, int b)
{
//循环求进位,直至进位为0
while(b!=0) //使用while循环,模拟多个加法器(每一位都有对应一个加法器)
{
int tmp = (a^b); //求本位
unsigned int carry = (unsigned int)(a&b)<<1; //计算进位。进位不存在 负 的情况。
a = tmp;
b=carry;
}
return a;
}
};