简体   繁体   中英

Can someone explain how this leetcode solution works with negative numbers?

This is a solution for leetcode problem 371 , Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.

Why we need MOD and MAX_INT and what is this part doing? ~(a & MAX_INT) ^ MAX_INT

def getSum( a, b):
    """
    :type a: int
    :type b: int
    :rtype: int
    """
    MOD     = 0xFFFFFFFF
    MAX_INT = 0x7FFFFFFF
    while b != 0:
        a, b = (a ^ b) & MOD, ((a & b) << 1) & MOD
    return a if a <= MAX_INT else ~(a & MAX_INT) ^ MAX_INT

print getSum4(-4,2)
-2

The solution is from this blog

The reason for MOD , MAX_INT and ~(a & MAX_INT) ^ MAX_INT is to simulate 32-bit integers. This is needed because in Python integers are not bounded.

After doing a calculation, & MOD is used to only keep the 32-bit least significant bits of the result. In systems where integers are only 32-bits, this is effectively what happens; the extra bits are simply dropped.

The usage of MAX_INT is to properly deal with what would be an integer overflow with 32-bit integers. If you add 0x40000000 and 0x40000000 , you'll get 0x80000000 , which in Python is just a positive integer. With 32-bit integers, this would be an overflow and the value is equal to -0x80000000 .

The a & MAX_INT is to remove the most-significant bit, which in 32-bit integers is essentially used as sign. The ~(...) ^ MAX_INT is a way to extend the 31-bit number to the number of bits actually used. For example, if Python would only use 42 bits, -0x80000000 would be represented as 0xff80000000 . In other words, just set every bit beyond the least significant 31 bits to 1 . (Doing ~x is the same as doing x ^ 0xff...ff , so ~x ^ MAX_INT is the same as x ^ (0xff..ff MAX_INT) and x ^ 0xff...ff80000000 and even x | 0xff...ff80000000 if x "uses" only 31 bits).

Of course, Python conceptually doesn't have a fixed number of bits it uses, but you can kind of look at it as if there will be an infinite number of bits set to 1. It just doesn't store all those bits, just like it doesn't store all 0 bits in positive numbers (eg 0x00...001).

An alternative way would be to do ~x ^ MOD , where you use that the 32nd bit is already correctly set.

I'm not surprised you're having a hard time trying to understand that code, definitely it works alright but I'd recommend you to start from scratch. First be sure you master bit operators, integer representation of numbers and two's complement for negative ones. Then just try to understand these 2 simpler functions with a couple of tests:

def add_32bits_buggy(a, b):
    MOD = 0xFFFFFFFF

    while (a != 0):
        c = (b & a) & MOD
        b = (b ^ a) & MOD
        a = (c << 1) & MOD

    return b


def add_32bits(a, b):
    MOD = 0xFFFFFFFF
    MAX_INT = 0x7FFFFFFF

    while (a != 0):
        c = (b & a) & MOD
        b = (b ^ a) & MOD
        a = (c << 1) & MOD

    if b <= MAX_INT:
        return b
    else:
        return ~(b & MAX_INT) ^ MAX_INT

# value to test edge_cases
max_v = 0xFFFFFFFF

# Positive integers
i = 1
while i <= max_v:
    i *= 2
    a, b = max_v + 1, i
    print "{0:10d}\t{1:10d}".format(
        add_32bits(a, b), add_32bits_buggy(a, b),
    )

print '-'*80

# Negative integers
i = 1
while i <= max_v:
    i *= 2
    a, b = max_v + 1, i
    print "{0:10d}\t{1:10d}".format(
        add_32bits(a, -b), add_32bits_buggy(a, -b),
    )

The function add_32bits_buggy will answer your question "Why we need MOD and MAX_INT and what is this part doing? ~(a & MAX_INT) ^ MAX_INT ". Then add_32bits (which is equivalent to your original code) will show how those cases are fixed because of the return.

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM