/*
* @lc app=leetcode.cn id=371 lang=java
*
* [371] 两整数之和
*/
// @lc code=start
class Solution {
public int getSum(int a, int b) {
int addBit;
/**
看几个例子分析存在的情况:
EG1:
a = 0x0011 -> 3 = 1 + 2
b = 0x0100 -> 4 = 0 + 0 + 4
a + b = 0x0111 -> 7 = 1 + 2 + 4 [类似10进制的加法不过这里是2进制的加法,当和超过等于2时进一位,不过这个例子没有进位的情况]
模拟下面的执行过程:
第1次循环:
addBit = 0x0000 -> 0
a = 0x0111 -> 7
b = addBit
退出因为 b = 0
返回结果 a = 7
这是最简单的情况了
EG2:
a = 0x0011 -> 3 = 1 + 2
b = 0x0110 -> 6 = 0 + 2 + 4
a + b = 0x1001 -> 9 = 1 + 0 + 0 + 8 [类似10进制的加法不过这里是2进制的加法,当和超过等于2时进一位]
模拟下面的执行过程:
第1次循环:
addBit = 0x0100 -> 4 = 0 + 0 + 4
a = 0x0101 -> 5 = 1 + 0 + 4
b = addBit
第2次循环:
addBit = 0x1000 -> 8 = 0 + 0 + 0 + 8
a = 0x0001 -> 1 = 1
b = addBit
第3次循环:
addBit = 0x0000 -> 0
a = 0x1001 -> 9 = 1 + 0 + 0 + 8
b = addBit
退出因为 b = 0
返回结果 a = 9
EG3:
再加上负数的情况基本就包括所有情况了
a = 0x0000 ... 0011 -> 3 = 1 + 2 <- 补码、原码[符号位左边第一位,正数为0,负数为1]
b = 0x1111 ... 1111 <- 补码[负数在计算机中的存储形式]
0x1000 ... 0000 <- 反码[补码符号位不变其它位按位取反]
0x1000 ... 0001 -> -1 = 1 <- 原码[反码符号位不变加1]
a + b = 0x0000 ... 0010 -> 2 = 0 + 2 [类似10进制的加法不过这里是2进制的加法,当和超过等于2时进一位]
模拟下面的执行过程:
第1次循环:
addBit = 0x0000 ..0 0110 -> 6 = 0 + 2 + 4
a = 0x1111 ..1 1100 -> 0x1000 ..0 0011 -> 0x1000 ..0 0100 -> -4 = -(0 + 0 + 4)
[使用上面的方法:补码 -> 反码 -> 原码-> 值]
b = addBit
第2次循环:
addBit = 0x0000 ..0 1000 -> 8 = 0 + 0 + 0 + 8
a = 0x1111 ..1 1010 ->
b = addBit
第3次循环:
addBit = 0x0000 ..1 0000 -> 16 = 0 + 0 + 0 + 0 + 16
a = 0x1111 ..1 0010 ->
b = addBit
...
[这里数字用的都是32位的整数]
第30次循环:
addBit = 0x1000 ..0 0000 -> 16 = 0 + 0 + 0 + ... + 2^32
a = 0x1000 ..0 0010 ->
b = addBit
第31次循环:
addBit = 0x0000 ..0 0000 -> 0
a = 0x0000 ..0 0010 -> 2 = 0 + 2
b = addBit
退出因为 b = 0
返回结果 a = 2
由这三个例子我们可以知道基本的计算方式,这里其实对于负数可以有一些优化的情况,欢迎大家讨论分享
*/
while(b != 0){
// 记录a、b相同位,即对应位相同则记为1,且统一将整体向左移动一位
addBit = ((a & b) << 1);
// 记录a、b不同位,即对应位不同则记为1
a = (a ^ b);
// 根据b是否大于零判断是否继续循环
b = addBit;
}
return a;
}
}
// @lc code=end