Concatenating integers and floating point instability
Suppose we have two integers, a
and b
, their concatenation may be simply calculated by:
def concat_simple(a, b):
return int(str(a) + str(b))
This implementation is correct, but converting integers to strings and back to an integer is slow. It would be faster if we could somehow not perform any string conversions.
Mathematically, for \(b \neq 0\), the following is true: $$ concat(a, b) = a \times 10 ^ {\lfloor log_{10}b \rfloor + 1} + b $$
Translating the above into Python:
from math import log
def concat(a, b):
if b == 0:
return a * 10
upper = a * 10**int(log(b, 10) + 1)
return upper + b
>>> concat(1234, 5678)
12345678
>>> concat(100, 1000)
101000 # Incorrect!
Our concat
function seems correct, but concat(100, 1000)
returns 101000
rather than 1001000
— why? The reason is due to the limited precision of floating point numbers. In this case, log(1000, 10)
is 2.9999999999999996
, so int(log(1000, 10) + 1)
returns 3
rather than 4
. To handle the imprecision, we can check if upper <= a * b
, and if so, multiply it by 10
to get the correct answer.
def concat(a, b):
if b == 0:
return a * 10
upper = a * 10**int(log(b, 10) + 1)
if upper <= a * b:
upper *= 10
return upper + b
Now concat(100, 1000) == 1001000
.