# Python 3.5: 552961 # Serhiy's patch: 504243 # using bits: 546250 # using bits and better log2(10) approxiation: 483424 import math PyLong_SHIFT = 30 _PyLong_DECIMAL_SHIFT = 9 _PyLong_DECIMAL_BASE = 10 ** _PyLong_DECIMAL_SHIFT def exact_decimalbase_digits(x): digits = 0 while x > _PyLong_DECIMAL_BASE: digits += 1 x //= _PyLong_DECIMAL_BASE return digits def size(x): return (x.bit_length() + PyLong_SHIFT - 1) // PyLong_SHIFT def math_decimalbase_digits(x): return 1 + math.floor(math.log2(x) / math.log2(_PyLong_DECIMAL_BASE)) def old_decimalbase_digits(x): bits = size(x) * PyLong_SHIFT return 1 + bits // (3 * _PyLong_DECIMAL_SHIFT) def new_decimalbase_digits(x): # Serhiy's patch (issue #25402) digits = size(x) d = (33 * _PyLong_DECIMAL_SHIFT) // (10 * PyLong_SHIFT - 33 * _PyLong_DECIMAL_SHIFT) return 1 + digits + digits // d def new_decimalbase_digits(x): # better estimation: use number of bits, not number of 30-bit digits bits = x.bit_length() # log2(10) = 3.321928094887362 # approximate to 3 (lower-bound) return 1 + bits // (3 * _PyLong_DECIMAL_SHIFT) def new_decimalbase_digits(x): # better estimation: use number of bits, not number of 30-bit digits bits = x.bit_length() # log2(10) = 3.321928094887362 # approximate to 33219 / 10000 (lower-bound) return bits * 10000 // (33219 * _PyLong_DECIMAL_SHIFT) total_old = 0 total_new = 0 def numbers(): yield from range(1, 1500) for digits in range(1, 1500): x = 10 ** digits yield x -1 yield x yield x +1 for bits in range(1, 1500): x = 2 ** bits yield x -1 yield x yield x +1 for x in numbers(): exact = exact_decimalbase_digits(x) old = old_decimalbase_digits(x) assert old >= exact, (x, exact, old, size(x)) new = new_decimalbase_digits(x) assert new >= exact, x assert old >= new, x total_old += old total_new += new print("Total old: %s" % total_old) print("Total new: %s" % total_new)