python 中的大整数的意外结果

Unexpected result for a large integer in python

我写了一个简单的程序来计算 n+1 中的位数,其中 n 很大 integer.The 下面的测试用例输出答案为 34,但答案是 33。 测试用例 - 99999999999999999999999999999990

代码-

  #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)

当我输入一个较小的整数时,比如 10 位数字,它会显示正确答案,例如 当输入=9999999990时,输出为10,正确。

math.log10() 将计算为双精度浮点数。它没有足够的精度来区分结果和数字 33。您可以使用 mpmath 以更高的精度评估 log10。此代码对我有用:

   #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)

请注意,精度设置为 127 位。在评估一个 40 位数字时,我们将 运行 陷入与之前相同的问题。当 40 位数字非常接近 10^41 时,log10 的结果可能会比 41 多一点,而实际值会少一点。这就是为什么将其转换为整数会产生 41 的原因。 让我们估计多少精度就足够了:log10(x) 的推导是 1 / (x * ln(10))。所以 log10(x+1) - log10(x) 对于高 x 大约是 1 / (x * ln(10) )。我们需要大约 Delta_y / y 的相对精度,其中 Delta_y 是 ( log10(x+1) - log10(x) ),y 是 log10(x)。我们可以用 log2( 1 / relative_precision ) 来估计二进制位数。这会产生 log2( x * ln(x) )。对于 39 个九和一个零的 x,这给了我们大约 139.4。所以如果我们把

mp.prec = 140

我们会得到正确的结果。确实

  #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) ) )

输出:

40
40

请注意,这可能不是评估位数的最佳方式。例如,您可以只使用一个循环,每一步除以 10。或者简单地说

print( len( str(inp) ) )