一、基本思路

异或运算提供两数相加后二进制非进位信息。与运算提供两数相加后二进制进位信息。

举例: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。我们在前面无视符号位了,所以需要还原数字。 alt

11110,直接用补码解读的话,前面默认还有0的,就像00011110这样,补码解读出来还是正数。所以不行。

因此要先异或:00011110^00011111=00000001;再取反按照补码解释:~00000001=11111110。这样,补码解读出来就是负数了。(注:python中,~运算符除了求反,还是二进制的补运算符,运算过后的二进制数字按照补码解释)

ps:除了用~(cusum^11111)这样的方式还原,最好理解的是用cusum-2的4次方(即31-2+1-32)的方式来还原。用到减法了。

处理负数问题时,逻辑是,对于python需要人为设置边界避免死循环(怎么死循环不太懂),又因为设置了边界,所以出现负数需要还原的情况,需要进行一些还原操作。