- 题目描述
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。 示例: 输入: a = 1, b = 1 输出: 2 提示: a, b 均可能是负数或 0 结果不会溢出 32 位整数
- 解法:位运算
求和如果不能用四则运算的话,那就只能用位运算了。
首先我们先观察下求和运算在二进制数中的规律,假如a = 5,b=17,计算a+b=?
a的二进制:101
b的二进制:10001
我们在计算过程中可以分三步走:
第一步:各位相加但是不进位,则a+b = 10100,此时没有计算倒数第二位的进位
第二步:各位相加只看进位,则a + b的进位为00010,只有倒数第二位有进位
第三步:把第一步和第二步的不进位相加结果和进位相加,则为a+b的结果(如果第一步和第二步仍然相加有进位,依然递归相加下去)
好的,那我们再看看第一步的相加不进位怎么实现呢?0+0,1+1的结果都是0(因为进位了),0+1,1+0的结果都是1,这其实就是一个异或运算(^)的操作!
再来,第二步的只计算进位,那更简单了,进位什么时候有呢,当且只有两个相加的位数均为1的时候才有,那这样的位运算刚好就是与运算(&),但这样还不够,进位是进在左边的,那么还需要对两个位数相与后左移(<<)。
接着,就是循环重复,直到没有进位就说明已经加完了!
需要注意的是,在python的存储方式中,负数的计算比较特别也比较复杂!
首先我们看看补码:
正数的补码是它本身,负数的补码是符号位(左边第一位)不变,其余位求反再加1
获取负数补码:
Python中正负数都是以补码的形式存在的,为了获取负数(十进制)的补码,需要手动将其和十六进制数0xffffffff(8gef)进行按位与操作,可理解为舍去此数字 32 位以上的数字(将 32 位以上都变为 00 ),从无限长度变为一个 32 位整数。
返回前数字还原:
若补码 aa 为负数( 0x7fffffff 是最大的正数的补码 ),需执行 ~(a ^ x) 操作,将补码还原至 Python 的存储格式。 a ^ x 运算将 1 至 32 位按位取反; ~ 运算是将整个数字取反;因此, ~(a ^ x) 是将 32 位以上的位取反,1 至 32 位不变。
代码:
class Solution: def add(self, a: int, b: int) -> int: x = 0xffffffff a , b = a & x, b & x while b != 0: a, b = a ^ b, (b & a) << 1 & x #异或,相与再左移 return a if a <=0x7fffffff else ~(a ^ x)
参考: