版权声明:本文参考网络文章。
难度:普通
要求:
给出两个整数a和b, 求他们的和, 但不能使用 +等数学运算符。
** 注意事项
你不需要从输入流读入数据,只需要根据aplusb的两个参数a和b,计算他们的和并返回就行。
说明
a和b都是 32位
整数么?
是的
我可以使用位运算符么?
当然可以
样例如果 a=1并且 b=2,返回3
思路:
用位运算实现加法也就是计算机用二进制进行运算,32位的CPU只能表示32位内的数,这里先用1位数的加法来进行,在不考虑进位的基础上,如下
1 + 1 = 0
1 + 0 = 1
0 + 1 = 1
0 + 0 = 0
很明显这几个表达式可以用位运算的“^”来代替,如下
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
这样我们就完成了简单的一位数加法,那么要进行二位的加法,这个方法可行不可行呢?肯定是不行的,矛盾就在于,如何去获取进位?要获取进位我们可以如下思考:
0 + 0 = 0
1 + 0 = 0
0 + 1 = 0
1 + 1 = 1
//换个角度看就是这样
0 & 0 = 不进位
1 & 0 = 不进位
0 & 1 = 不进位
1 & 1 = 进位
正好,在位运算中,我们用“<<”表示向左移动一位,也就是“进位”。那么我们就可以得到如下的表达式
//进位可以用如下表示:
(x&y)<<1
到这里,我们基本上拥有了这样两个表达式
x^y //执行加法
(x&y)<<1 //进位操作
现总结如下:
定理1:
设a,b为两个二进制数,则a+b = a^b + (a&b)<<1。证明:a^b是不考虑进位时加法结果。当二进制位同时为1时,才有进位,因此 (a&b)<<1是进位产生的值,称为进位补偿。将两者相加便是完整加法结果。
定理2:
使用定理1可以实现只用位运算进行加法运算。证明:利用定理1中的等式不停对自身进行迭代。每迭代一次,进位补偿右边就多一位0,因此最多需要加数二进制位长度次迭代,进位补偿就变为0,这时运算结束。
class Solution {
/*
* param a: The first integer
* param b: The second integer
* return: The sum of a and b
*/
public int aplusb(int a, int b) {
// write your code here, try to do it without arithmetic operators.
if(a==0)return b;
if(b==0)return a;
int x = a^b; //记录不进位数
int y = (a&b)<<1; //记录进位数
return aplusb(x,y); //然后递归 上述不进位结果 + 进位结果,最终进位为0,则返回最终结果
}
};