解题思路
考察对计算机加法的理解,计算机对任何计算实际上都是二进制数之间的位运算。所以本题就是让我们从位运算的角度来考虑问题。
基于二进制加法,考虑有两种情况:
- 两二进制数相加,无进位产生。如:
9 + 6:
1 0 0 1 (转换为异或运算) 1 0 0 1
+ 0 1 1 0 -------------> ^ 0 1 1 0
= 1 1 1 1 = 1 1 1 1
此时,两二进制数相加的结果就是这两个数异或的结果!
- 两二进制数相加,产生进位。如:
9 + 15:
1 0 0 1 (转换为异或运算) 1 0 0 1
+ 1 1 1 1 -------------> ^ 1 1 1 1
= 1 1 0 0 0 = 0 1 1 0
此时,显然不再是简单的直接进行异或运算。应采用这样的方式:
- 将两二进制数进行按位与运算(如下),以及异或运算(异或运算过程如上)
9 + 15:
1 0 0 1
& 1 1 1 1
= 1 0 0 1
- 将按位与运算的结果左移一位(目的是得到进位
1
)
(左移1位)
1 0 0 1 ------------> 1 0 0 1 0
- 将左移一位后的结果与异或结果相加(注意:此相加过程让然是应该按照位运算进行,这说明该程序需要进行递归…此处为了演示这样的做法是正确的,所以直接进行加运算来验证结果):
1 0 0 1 0
+ 0 1 1 0
= 1 1 0 0 0
(注意:这里也产生了进位的,尽管不是在最高为上产生的进位~ 也属于第二种情况)
可以看出,这个结果正是(9+15)的结果。
还并不是很清楚有进位时的这一运算过程为什么就能得到正确的结果。。。
我们进行一下上面提到的递归的过程分析:
- 即先另
1 0 0 1 0
,0 1 1 0
做与运算以及异或运算,然后与运算的结果左移一位,再与异或运算的结果相加。自己动手算一下吧,你会发现,又出现了一次递归~ 继续重复上述步骤,你会发现最终结果是正确的~- 然后,你还可以试试位运算时有两位都产生进位的情况,如(6+6) ----> (0110 + 0110),会发现该程序让然适用。
- 还可以试试负数相加。由于补码的存在,使得减法也在底层转换为加法,因此,该程序仍然适用。
分析完上面的两种情况,应该思考如何区分这两种情况呢?即,if中的判断语句该怎么写呢?
答案:由于有进位的情况是该位上两个1
相加,所以我们就做按位与运算,一旦对应位上的与运算的结果为1
,就说明这里将产生进位(只有两运算数都是1
时,与运算的结果才是1
)。反之,如果每一位都没有进位,那么与运算的结果将为0
。
程序实现(Python)
def ABsum(num1, num2):
# 没有产生进位的情况
if (num1 & num2 == 0):
sum = num1 ^ num2
# 产生了进位的情况
else:
sum = ABsum((num1 & num2) << 1, num1 ^ num2)
#print('else _ sum = %d' % sum) # 测试
return(sum)
print(ABsum(6, 6))
这里
print('else _ sum = %d' % sum)
语句中sum
的值总是最后结果,与裴波那契数列递归不太一样的~ 因为这里最终递归的那一次的结果就是我们想要的结果,而裴波那契数列递归出的结果需要返回后进行一定的整合才真正得到最终结果。
如果你觉得递归会使得效率较低,那么还可以使用循环:
def ABsum(num1, num2):
while num1 & num2 != 0:
t1, t2 = num1, num2
num1 = (t1 & t2) << 1
num2 = t1 ^ t2
return num1 ^ num2
print(ABsum(9, 15))
如果想显得厉害一点…你可以只用一条长一些的语句实现:
def ABsum(num1, num2):
return num1 ^ num2 if num1 & num2 == 0 else ABsum((num1 & num2) << 1, num1 ^ num2)