一、基本思路
异或运算提供两数相加后二进制非进位信息。与运算提供两数相加后二进制进位信息。
举例:5+7
- 第一步:
5:101
7:111
异或运算得到非进位信息:010
与运算得到进位信息:101,此时需要左移位一位变成1010,再相加(用010加上1010就能得到最终结果,那么010怎么和1010做加法呢?还是同样采用异或和与运算结合的方法)
- 第二步: 010和1010
异或运算:1000
与运算:0010,左移位一位变成0100
- 第三步: 1000和0100
异或运算:1100
与运算:0000,与运算后变成0,说明没有进位信息了,循环结束,结果返回异或运算的终止值。
都是正数相加的话,上面流程没什么问题。如果是过程结果中出现负数,对于python就有点麻烦。
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param num1 int整型
# @param num2 int整型
# @return int整型
#
class Solution:
def Add(self , num1: int, num2: int) -> int:
cusum=num1#cusum用来记录非进位相加信息
forward=num2#forward用来记录进位信息
while forward!=0:# 当不再有进位的时候终止循环
cusum=(num1^num2)& 0xFFFFFFFF
forward=((num1 & num2)<<1)& 0xFFFFFFFF#这里的& 0xFFFFFFF可以不需要?
#num1用cusum更新,num2用forward更新
num1=cusum
num2=forward
if cusum>>31==0:#意思cusum是个正数时
return cusum
else:
return ~(cusum^0xFFFFFFFF)
二、处理负数问题
补充知识: (1)在计算机系统中,数值一律用补码来表示和存储。正数的原码、反码、补码都一样;负数的补码等于该数的反码加1。 举例:-1
原码:00001(以5位举例,第一位是符号位)
反码:11110
补码:11111
举例:-2
原码:00010(以5位举例,第一位是符号位)
反码:11101
补码:11110
(2)C++环境有边界有符号位。可以不用设置边界,过程中出现负数也能返回正确结果。 举例:(-1)+(-1)、(-1)+14
11111+11111=11110,因为知道第一个1是符号位,1代表负数,所以能返回正确的结果11110,即-2。11111+01111,同样返回正确结果01110,即14。
(3)对于python,没有边界,需要人为设置边界避免死循环(怎么死循环不太懂)。举例设置边界为11111(5位是边界)。cusum= a & 11111相当于无视符号位,直接转为无符号数。(注:0xFFFFFFFF代表16进制下的边界,按二进制表示的话,对应4*8=32位)
举例,比如计算过程中出现cusum为11110的情况,使用符号位情况下,本来代表的是-2。如果无视符号位,会解读成31-2+1。我们在前面无视符号位了,所以需要还原数字。
11110,直接用补码解读的话,前面默认还有0的,就像00011110这样,补码解读出来还是正数。所以不行。
因此要先异或:00011110^00011111=00000001;再取反按照补码解释:~00000001=11111110。这样,补码解读出来就是负数了。(注:python中,~运算符除了求反,还是二进制的补运算符,运算过后的二进制数字按照补码解释)
ps:除了用~(cusum^11111)这样的方式还原,最好理解的是用cusum-2的4次方(即31-2+1-32)的方式来还原。用到减法了。
处理负数问题时,逻辑是,对于python需要人为设置边界避免死循环(怎么死循环不太懂),又因为设置了边界,所以出现负数需要还原的情况,需要进行一些还原操作。