LeetCode 371 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.
这里考察的是是否理解计算机如何实现加减法运算。
加法运算由多位串联的全加器实现,而每个全加器实际上又由半加器组成。如下图给出了一个4bit的加法器。
假设有两个bit:a0和b0,半加器的逻辑:
$s0 = a0 xor b0$
$s0 = a0 & bo$
假设有两个4bit的整数相加:a3a2a1a0 + b3b2b1b0,则
$sum = a xor b = (a3 xor b3) (a2 xor b2) (a1 xor b1) (a0 xor b0)$
每一位分别异或运算,求取不考虑进位的各位之和
$carry = a & b = (a3 & b3) (a2 & b2) (a1 & b1) (a0 & b0)$
每一位分别与运算,求取当前这种不考虑进位的加法,各位两个bit相加后产生的进位
下面就到了最trick的部分,由于当前的sum未考虑进位,因为加上carry才是真正的结果。
那carry应该怎么作用到sum上呢?实际上carry是每一bit的进位(此处是4bit),第i位的进位应该作用到i+1位上,用公式可以表达为
$sum = sum + 2 * carry = s3s2s1s0 + c3c2c1c0 << 1$
要注意的是,sum和carry的相加还会产生新的sum和carry,由于高位的carry先传递给高位,但低位的carry还没有传递到,因此sum与carry的相加需要循环多次,知道carry为0时,加法才真正结束。这里的carry左移,与半加器中carryout的传递相对应,第一次左移代表,a0b0的carryout传递完毕,不再考虑a0b0的部分,第二次左移代表a1b1的carryout传递完毕,不再考虑a1b1,以此类推直到a3b3。
这里的carry整体左移,再直接作用到sum上有一些难以理解,特别是sum直接异或carry求取不考虑进位的和,这里一开始可能感觉这个加法不正确,但实际上,第i次的sum xor carry仅仅是确定了倒数第i位的和,剩余的carry信息仍在传递且加法没有结束,这里一定能够要能够理解这种carry传递的思维。
public class Solution {
public int getSum(int a, int b) {
while (b != 0) {
int carry = a & b;
a = a ^ b;
b = carry << 1;
}
return a;
}
}