Sum of Two Integers
Calculate the sum of two integers a and b, but you are not allowed to use the operator +
and -
.
Example:
Given a = 1 and b = 2, return 3.
Credits:
Special thanks to @fujiaozhu for adding this problem and creating all test cases.
Subscribe to see which companies asked this question
本题是考察计算机内部实现加法的原理。
一位二进制加法
首先给出一位二进制加法的真值表,然后我们通过分析真值表来得出如果进行二进制加法的规则。
一位二进制加法真值表:(对应于硬件中的半加器)
x | y | sum | carry |
0 | 0 | 0 | 0 |
0 | 1 | 1 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
分析上面一位二进制加法的真值表,可以看出和其实就是x XOR y的结果。而进位恰好是x AND y的结果。下面提供XOR和AND的真值表,进行验证。
x XOR y真值表:
x | y | output |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
x AND y真值表:
x | y | output |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
多位二进制加法
因此进行一位二进制加法,只要对x和y进行XOR和AND运算就可以得出和以及进位。如果要求多位的二进制加法,则要把低位传上来的进位也要计算进去。修改一位二进制加法的真值表,在输入部分中加入低位传入的进位,然后对计算结果进行修正就可以得到多位二进制加法的真值表了。
多位二进制加法真值表:(对应于硬件中的全加器)
x | y | icarry | sum | ocarry |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 | 1 |
1 | 0 | 0 | 1 | 0 |
1 | 0 | 1 | 0 | 1 |
1 | 1 | 0 | 0 | 1 |
1 | 1 | 1 | 1 | 1 |
分析上面的真值表就可以总结出,多位二进制加法的规则了。如下:
sum = (x XOR y) XOR icarry
ocarry = (x AND y) OR (icarry AND (x XOR y)) = (x AND y) OR (y AND icarry) OR (icarry AND x)
利用以上的分析结果,可将x, y的每一位级联计算,先计算x和y的第零位,该位的输入进位(icarry=0)为零,将计算所得的进位传入到x和y的第一位的计算中,依次进行直到计算完最高位为止,此时将每一位计算所得的和连接起来就是最终的和,最高位计算所得的进位就是最终的进位。至此,二进制的加法应该没有什么问题了,很简单XOR为和,AND为进位。计算机中的加法也是使用这种原理来实现的,有兴趣的可以看看《编码的奥秘》这本书。
通过以上分析似乎用代码实现计算机加法的方法已经很明了了,将参加计算的x,y分别一位一位的进行XOR和AND,然后将结果打印出来,OK完事了,很简单不是吗?但问题是如果将x和y的每一位拆分,然后记录每一位计算后所得的进位,然后做为下一位的进位输入。仔细想想又似乎是问题多多啊,烦啊。其实也不然我们用代码实现的时候已经不需要再将每一位拆分计算了(如果你确实像模拟计算机硬件的执行过程也可以这么做,只是这样做很麻烦,而且计算的速度比较慢)。首先,我们通过对x和y进行&位运算,得出每一位上的进位。然后对x和y进行^位运算,得出没有加进位的和。最后将所得的和当做新的x,所得的进位往左移一位(第零位的进位输入为0)当做新的y,继续做上面的步骤,直到进位为0,此时x中保存的就是我们要求的x和y的和了。
代码如下:
1 class Solution(object): 2 def getSum(self, a, b): 3 """ 4 :type a: int 5 :type b: int 6 :rtype: int 7 """ 8 while (b != 0): 9 c = a ^ b 10 b = (a & b) << 1 11 a = c 12 return a 13
posted on 2016-07-11 12:37 stackhacks 阅读(354) 评论(0) 编辑 收藏 举报