I was trying to solve an old question:
Write a function that add two [integer] numbers A and B. You should not use + or any arithmetic operators.
The best solution is like this, quoted from "LintCode-A+B Problem":
For a + b in any base, we can treat the plus as two part: 1. a + b without carry; 2. the carry generated by a +b. The a+b then equals to part 1 plus part 2. If part1+part2 generates more carry, we can then repeat this procedure, until there is no carry.
I can understand this algorithm and everything seems good, so I tested it on lintcode with code pasted below.
class Solution:
"""
@param a: The first integer
@param b: The second integer
@return: The sum of a and b
"""
def aplusb(self, a, b):
while b != 0:
carry = a & b
a = a ^ b
b = carry << 1
return a
But surprisingly, it gave me Time Limit Exceeded
error in test case [100, -100]
. So I ran it locally and print a, b for every loop:
(-8, 8)
(-16, 16)
(-32, 32)
(-64, 64)
(-128, 128)
(-256, 256)
(-512, 512)
(-1024, 1024)
(-2048, 2048)
(-4096, 4096)
(-8192, 8192)
(-16384, 16384)
(-32768, 32768)
(-65536, 65536)
(-131072, 131072)
...
The calculation is correct, so I think this algorithm does not work for such input but when I wrote the same algorithm in C++, it just works:
class Solution {
public:
int aplusb(int a, int b) {
while (b!=0){
int carry = a & b;
a = a^b;
b = carry << 1;
}
return a;
}
};
I don't know what should be asked exactly, basically the questions are:
- Why does C++ give the correct output
0
while Python doesn't? - If I use Python, how do I modify this algorithm to make it work?
The binary, 2's complement representation of
-4
isYes, I really do mean infinitely many
1
's to the left; this is a binary repeating numeral. Technically,4
is a repeating numeral too:it's just repeating
0
's to the left.Your addition problem is
The operators
^
,<<
, and&
have no trouble computing with infinitely many binary digits, but the problem is that there are infinitely many carries, and you are computing them one digit at a time. This will never finish.Thus, you have to recognize when this algorithm will get stuck in this situation and do something else to account for it.
You don't run into this problem in C/C++, because, for example, if
int
is 32-bits, then all of the digits except for the rightmost 31 digits get collapsed into a single bit, so it does the remaining carries all at once.However, technically speaking, the meaning of left shifting an
int
is in terms of the value as an integer, rather than as a bit pattern, so you are invoking undefined behavior if the two most significant bitscarry
are ever different, because thencarry << 1
would produce an overflow).