1. A + B 问题
给出两个整数 aa 和 bb , 求他们的和。
样例
样例 1:
输入: a = 1, b = 2
输出: 3
样例解释:
返回a+b的结果.
样例 2:
输入: a = -1, b = 1
输出: 0
样例解释:
返回a+b的结果.
挑战
显然你可以直接 return a + b,但是你是否可以挑战一下不这样做?(不使用++等算数运算符)
说明
a和b都是 32位
整数么?
代码
class Solution:
"""
@param a: An integer
@param b: An integer
@return: The sum of a and b
"""
def aplusb(self, a, b):
# write your code here
if (a == 0):
return b
if (b == 0):
return a
x1 = a ^ b
x2 = (a & b) << 1
return aplusb(x1, x2)
1.1 正数
十进制下:5 + 7 = 12
5: 0101
7: 0111
二进制下两数求和,分三步:
各位值相加,不算进位值,二进制亦或运算
计算进位值,二进制与运算,然后左移一位;
对1,2步的结果,重复以上两步骤
两数之和就是不计算进位值加上进位值,直到没有进位
第二部为什么要左移?
当你在十进制下计算5+7时,进位向前一位进1,也就是相当于左移
5 + 7的详细计算:
第一次:
亦或:0101^0111 = 0010,没有进位的值。
与:0101&0111 = 0101,等于1的位说明这一位是要产生进位的。而进位是要向前进一位,所以要左移,
0101 ,两个位置为1,说明是有两个位置需要进位,左移运算,0101<<1 = 1010
第二次:
0010^1010 = 1000
(0010&&1010)<<1 = 0100 # 还有进位,需要继续加
第三次:
1000^0100 = 1100
(1000&&0100) <<1= 0000 # 没有进位
进位为0,返回第一步的结果。
1.2 负数
博客上好多教程都是以正数为例来解释,让好多读者误认为二进制的运算是在源码上进行的。
实际情况是用补码运算的!!!
因为正数的源码、反码、补码是相等的,所以大家误认为是用的源码。
python3 中最高位1表示负数,最高位0表示正数
(个人认为,用补码运算是因为可以把符号位直接参与运算)
源码转化成补码:源码转化成反码(符号位1不变,其他位改变),然后反码+1
补码转化为源码:你只需要记住,补码的补码就是源码
所以补码转反码,然后+1
例如 -2 + 8
用8位二进制表示:
-2 源码 :1000 0010;反码:1111 1101;补码:1111 1110
8 源码/反码/补码:0000 1000
用补码运算结果如下:
1、1111 1110^0000 1000 = 1111 0110 (负数)转化成源码:1000 1010 = -10
2、(1111 1110&0000 1000)<<1 = 0001 0000 (正数),源码和补码一样:0001 0000 = 16
这是用补码运算的例子。
继续运算:
进位为16,继续计算1,2步,你会发现进入死循环。
因为:python3实现不会溢出,溢出的最高位不会舍弃掉。详细请看博文:https://www.jianshu.com/p/21fd1598d4ae
这种方法在c,c++,java中没有问题。但在python3中会有问题,python3存的正数是无限大的