harshadwani
harshadwani

Reputation: 47

Unexpected result for a large integer in python

I wrote a simple program to count the number of digits in n+1 where n is a large integer.The following test case outputs the answer as 34 but the answer is 33. Test case - 999999999999999999999999999999990

Code -

  #python3
import math
inp = eval(input())

if inp > 0:
    digits = int(math.log10(inp+1))+1
elif inp == 0:
    digits = 1
else:
    digits = int(math.log10(-inp))+2
print(digits)

When I input a smaller integer,say 10 digits, it shows the correct answer, for example when input = 9999999990, output is 10, which is correct.

Upvotes: 0

Views: 123

Answers (1)

p0ny
p0ny

Reputation: 317

math.log10() will evaluate to a double precision floating point number. It doesn't have enough precision to tell the result and the number 33 apart. You can use mpmath to evaluate log10 with higher precision. This code worked for me:

   #python3
from mpmath import mp
mp.prec = 127 # set the precision to 127 bits

inp = int('999999999999999999999999999999990')

if inp > 0:
    digits = int(mp.log10(inp))+1
elif inp == 0:
    digits = 1
else:
    digits = int(mp.log10(-inp))+2
    
print(digits)

Note that the precision is set to 127 bits. When evaluating a 40-digits number, we will run into the same problem as we had before. When the 40-digit number is very close to 10^41, the result of log10 might be a little bit more than 41 while the real value is a little bit less. This is why converting it so an integer yields 41. Let's estimate how much precision is sufficient: The derivation of log10(x) is 1 / (x * ln(10)). So log10(x+1) - log10(x) is about 1 / (x * ln(10) ) for high x. We need a relative precision of about Delta_y / y, where Delta_y is ( log10(x+1) - log10(x) ) and y is log10(x). We can estimate the number of binary digits with log2( 1 / relative_precision ). This yields us log2( x * ln(x) ). For an x of 39 nines and one zero, this gives us about 139.4. So if we put

mp.prec = 140

we will get the correct result. Indeed

  #python3
from mpmath import mp
mp.prec = 140

inp = int(39 * '9' + '0')

if inp > 0:
    digits = int(mp.log10(inp))+1
elif inp == 0:
    digits = 1
else:
    digits = int(mp.log10(-inp))+2
    
print(digits)
print( len( str(inp) ) )

outputs:

40
40

Note that this might not be the best way of evaluating the number of digits. You could for example just use a loop, dividing by 10 each step. Or simply put

print( len( str(inp) ) )

Upvotes: 1

Related Questions