不使用加法计算a+b的值
首先考虑十进制加法中,如8+15:
1、不考虑进位:各位相加:个位得8+5=13,个位为3;十位得0+1=1;结果为13
2、考虑进位:个位进位为10
3、1和2中的结果相加得13+10=23
按照上述思想考试二进制加法中:如1000+1111
1、不考虑进位:各位相加:1+1=0,1+0=1,0+1=1,0+0=0,与位运算中的亦或操作相同 a^b
2、考虑进位:显然只有1+1会出现进位,相对于这位的进位为10,即把与运算的结果往左移一位 (a&b)<<1
3、1和2中的结果相加直到不产生进位
以上分析来自lintCode
根据以上分析,我们可以得出一个结论:a+b = f(a+b) + m(a+b)
其中f(a+b)表示无进位的a+b,比如上面的13,m(a+b)表示进位结果,比如上面的10
在位运算中,异或运算通常也叫做无进位的加法,与运算刚好可以用来计算进位结果(因为只有 1&1 == 1,只有 1 + 1 会进位),所以我们又可以得出以下公式:a+b = a^b + (a&b)<<1,由于不能用加法,这个公式我们可以很容易的用递归实现:
int sum(int a, int b)
{
if (b == 0) {
return a;
}
int c = a^b;
int d = (a&b)<<1;
return sum(c, d);
}
非递归版本
前有公式:a+b = a^b + (a&b)<<1,其中 a 对应于 a^b ,b 对应于 (a&b)<<1,因为 ^ 在这里是加法,所以 a 代表无进位加法结果,b 代表进位信息,当没有进位信息时(b==0),计算结束,据此,我们可以写出如下非递归代码:
int sum(int a,int b)
{
/**
先计算进位结果 c
然后计算无进位结果 a
如果有进位,设置给b,进入下一次计算
*/
while (b != 0) {
int c = (a&b)<<1;
a = a^b;
b = c;
}
return a;
}
PS:对于递归运算,千万不要试图用大脑来计算每一次递归的结果!!!
网友评论