_pylong.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. """Python implementations of some algorithms for use by longobject.c.
  2. The goal is to provide asymptotically faster algorithms that can be
  3. used for operations on integers with many digits. In those cases, the
  4. performance overhead of the Python implementation is not significant
  5. since the asymptotic behavior is what dominates runtime. Functions
  6. provided by this module should be considered private and not part of any
  7. public API.
  8. Note: for ease of maintainability, please prefer clear code and avoid
  9. "micro-optimizations". This module will only be imported and used for
  10. integers with a huge number of digits. Saving a few microseconds with
  11. tricky or non-obvious code is not worth it. For people looking for
  12. maximum performance, they should use something like gmpy2."""
  13. import re
  14. import decimal
  15. try:
  16. import _decimal
  17. except ImportError:
  18. _decimal = None
  19. def int_to_decimal(n):
  20. """Asymptotically fast conversion of an 'int' to Decimal."""
  21. # Function due to Tim Peters. See GH issue #90716 for details.
  22. # https://github.com/python/cpython/issues/90716
  23. #
  24. # The implementation in longobject.c of base conversion algorithms
  25. # between power-of-2 and non-power-of-2 bases are quadratic time.
  26. # This function implements a divide-and-conquer algorithm that is
  27. # faster for large numbers. Builds an equal decimal.Decimal in a
  28. # "clever" recursive way. If we want a string representation, we
  29. # apply str to _that_.
  30. D = decimal.Decimal
  31. D2 = D(2)
  32. BITLIM = 128
  33. mem = {}
  34. def w2pow(w):
  35. """Return D(2)**w and store the result. Also possibly save some
  36. intermediate results. In context, these are likely to be reused
  37. across various levels of the conversion to Decimal."""
  38. if (result := mem.get(w)) is None:
  39. if w <= BITLIM:
  40. result = D2**w
  41. elif w - 1 in mem:
  42. result = (t := mem[w - 1]) + t
  43. else:
  44. w2 = w >> 1
  45. # If w happens to be odd, w-w2 is one larger then w2
  46. # now. Recurse on the smaller first (w2), so that it's
  47. # in the cache and the larger (w-w2) can be handled by
  48. # the cheaper `w-1 in mem` branch instead.
  49. result = w2pow(w2) * w2pow(w - w2)
  50. mem[w] = result
  51. return result
  52. def inner(n, w):
  53. if w <= BITLIM:
  54. return D(n)
  55. w2 = w >> 1
  56. hi = n >> w2
  57. lo = n - (hi << w2)
  58. return inner(lo, w2) + inner(hi, w - w2) * w2pow(w2)
  59. with decimal.localcontext() as ctx:
  60. ctx.prec = decimal.MAX_PREC
  61. ctx.Emax = decimal.MAX_EMAX
  62. ctx.Emin = decimal.MIN_EMIN
  63. ctx.traps[decimal.Inexact] = 1
  64. if n < 0:
  65. negate = True
  66. n = -n
  67. else:
  68. negate = False
  69. result = inner(n, n.bit_length())
  70. if negate:
  71. result = -result
  72. return result
  73. def int_to_decimal_string(n):
  74. """Asymptotically fast conversion of an 'int' to a decimal string."""
  75. w = n.bit_length()
  76. if w > 450_000 and _decimal is not None:
  77. # It is only usable with the C decimal implementation.
  78. # _pydecimal.py calls str() on very large integers, which in its
  79. # turn calls int_to_decimal_string(), causing very deep recursion.
  80. return str(int_to_decimal(n))
  81. # Fallback algorithm for the case when the C decimal module isn't
  82. # available. This algorithm is asymptotically worse than the algorithm
  83. # using the decimal module, but better than the quadratic time
  84. # implementation in longobject.c.
  85. def inner(n, w):
  86. if w <= 1000:
  87. return str(n)
  88. w2 = w >> 1
  89. d = pow10_cache.get(w2)
  90. if d is None:
  91. d = pow10_cache[w2] = 5**w2 << w2 # 10**i = (5*2)**i = 5**i * 2**i
  92. hi, lo = divmod(n, d)
  93. return inner(hi, w - w2) + inner(lo, w2).zfill(w2)
  94. # The estimation of the number of decimal digits.
  95. # There is no harm in small error. If we guess too large, there may
  96. # be leading 0's that need to be stripped. If we guess too small, we
  97. # may need to call str() recursively for the remaining highest digits,
  98. # which can still potentially be a large integer. This is manifested
  99. # only if the number has way more than 10**15 digits, that exceeds
  100. # the 52-bit physical address limit in both Intel64 and AMD64.
  101. w = int(w * 0.3010299956639812 + 1) # log10(2)
  102. pow10_cache = {}
  103. if n < 0:
  104. n = -n
  105. sign = '-'
  106. else:
  107. sign = ''
  108. s = inner(n, w)
  109. if s[0] == '0' and n:
  110. # If our guess of w is too large, there may be leading 0's that
  111. # need to be stripped.
  112. s = s.lstrip('0')
  113. return sign + s
  114. def _str_to_int_inner(s):
  115. """Asymptotically fast conversion of a 'str' to an 'int'."""
  116. # Function due to Bjorn Martinsson. See GH issue #90716 for details.
  117. # https://github.com/python/cpython/issues/90716
  118. #
  119. # The implementation in longobject.c of base conversion algorithms
  120. # between power-of-2 and non-power-of-2 bases are quadratic time.
  121. # This function implements a divide-and-conquer algorithm making use
  122. # of Python's built in big int multiplication. Since Python uses the
  123. # Karatsuba algorithm for multiplication, the time complexity
  124. # of this function is O(len(s)**1.58).
  125. DIGLIM = 2048
  126. mem = {}
  127. def w5pow(w):
  128. """Return 5**w and store the result.
  129. Also possibly save some intermediate results. In context, these
  130. are likely to be reused across various levels of the conversion
  131. to 'int'.
  132. """
  133. if (result := mem.get(w)) is None:
  134. if w <= DIGLIM:
  135. result = 5**w
  136. elif w - 1 in mem:
  137. result = mem[w - 1] * 5
  138. else:
  139. w2 = w >> 1
  140. # If w happens to be odd, w-w2 is one larger then w2
  141. # now. Recurse on the smaller first (w2), so that it's
  142. # in the cache and the larger (w-w2) can be handled by
  143. # the cheaper `w-1 in mem` branch instead.
  144. result = w5pow(w2) * w5pow(w - w2)
  145. mem[w] = result
  146. return result
  147. def inner(a, b):
  148. if b - a <= DIGLIM:
  149. return int(s[a:b])
  150. mid = (a + b + 1) >> 1
  151. return inner(mid, b) + ((inner(a, mid) * w5pow(b - mid)) << (b - mid))
  152. return inner(0, len(s))
  153. def int_from_string(s):
  154. """Asymptotically fast version of PyLong_FromString(), conversion
  155. of a string of decimal digits into an 'int'."""
  156. # PyLong_FromString() has already removed leading +/-, checked for invalid
  157. # use of underscore characters, checked that string consists of only digits
  158. # and underscores, and stripped leading whitespace. The input can still
  159. # contain underscores and have trailing whitespace.
  160. s = s.rstrip().replace('_', '')
  161. return _str_to_int_inner(s)
  162. def str_to_int(s):
  163. """Asymptotically fast version of decimal string to 'int' conversion."""
  164. # FIXME: this doesn't support the full syntax that int() supports.
  165. m = re.match(r'\s*([+-]?)([0-9_]+)\s*', s)
  166. if not m:
  167. raise ValueError('invalid literal for int() with base 10')
  168. v = int_from_string(m.group(2))
  169. if m.group(1) == '-':
  170. v = -v
  171. return v
  172. # Fast integer division, based on code from Mark Dickinson, fast_div.py
  173. # GH-47701. Additional refinements and optimizations by Bjorn Martinsson. The
  174. # algorithm is due to Burnikel and Ziegler, in their paper "Fast Recursive
  175. # Division".
  176. _DIV_LIMIT = 4000
  177. def _div2n1n(a, b, n):
  178. """Divide a 2n-bit nonnegative integer a by an n-bit positive integer
  179. b, using a recursive divide-and-conquer algorithm.
  180. Inputs:
  181. n is a positive integer
  182. b is a positive integer with exactly n bits
  183. a is a nonnegative integer such that a < 2**n * b
  184. Output:
  185. (q, r) such that a = b*q+r and 0 <= r < b.
  186. """
  187. if a.bit_length() - n <= _DIV_LIMIT:
  188. return divmod(a, b)
  189. pad = n & 1
  190. if pad:
  191. a <<= 1
  192. b <<= 1
  193. n += 1
  194. half_n = n >> 1
  195. mask = (1 << half_n) - 1
  196. b1, b2 = b >> half_n, b & mask
  197. q1, r = _div3n2n(a >> n, (a >> half_n) & mask, b, b1, b2, half_n)
  198. q2, r = _div3n2n(r, a & mask, b, b1, b2, half_n)
  199. if pad:
  200. r >>= 1
  201. return q1 << half_n | q2, r
  202. def _div3n2n(a12, a3, b, b1, b2, n):
  203. """Helper function for _div2n1n; not intended to be called directly."""
  204. if a12 >> n == b1:
  205. q, r = (1 << n) - 1, a12 - (b1 << n) + b1
  206. else:
  207. q, r = _div2n1n(a12, b1, n)
  208. r = (r << n | a3) - q * b2
  209. while r < 0:
  210. q -= 1
  211. r += b
  212. return q, r
  213. def _int2digits(a, n):
  214. """Decompose non-negative int a into base 2**n
  215. Input:
  216. a is a non-negative integer
  217. Output:
  218. List of the digits of a in base 2**n in little-endian order,
  219. meaning the most significant digit is last. The most
  220. significant digit is guaranteed to be non-zero.
  221. If a is 0 then the output is an empty list.
  222. """
  223. a_digits = [0] * ((a.bit_length() + n - 1) // n)
  224. def inner(x, L, R):
  225. if L + 1 == R:
  226. a_digits[L] = x
  227. return
  228. mid = (L + R) >> 1
  229. shift = (mid - L) * n
  230. upper = x >> shift
  231. lower = x ^ (upper << shift)
  232. inner(lower, L, mid)
  233. inner(upper, mid, R)
  234. if a:
  235. inner(a, 0, len(a_digits))
  236. return a_digits
  237. def _digits2int(digits, n):
  238. """Combine base-2**n digits into an int. This function is the
  239. inverse of `_int2digits`. For more details, see _int2digits.
  240. """
  241. def inner(L, R):
  242. if L + 1 == R:
  243. return digits[L]
  244. mid = (L + R) >> 1
  245. shift = (mid - L) * n
  246. return (inner(mid, R) << shift) + inner(L, mid)
  247. return inner(0, len(digits)) if digits else 0
  248. def _divmod_pos(a, b):
  249. """Divide a non-negative integer a by a positive integer b, giving
  250. quotient and remainder."""
  251. # Use grade-school algorithm in base 2**n, n = nbits(b)
  252. n = b.bit_length()
  253. a_digits = _int2digits(a, n)
  254. r = 0
  255. q_digits = []
  256. for a_digit in reversed(a_digits):
  257. q_digit, r = _div2n1n((r << n) + a_digit, b, n)
  258. q_digits.append(q_digit)
  259. q_digits.reverse()
  260. q = _digits2int(q_digits, n)
  261. return q, r
  262. def int_divmod(a, b):
  263. """Asymptotically fast replacement for divmod, for 'int'.
  264. Its time complexity is O(n**1.58), where n = #bits(a) + #bits(b).
  265. """
  266. if b == 0:
  267. raise ZeroDivisionError
  268. elif b < 0:
  269. q, r = int_divmod(-a, -b)
  270. return q, -r
  271. elif a < 0:
  272. q, r = int_divmod(~a, b)
  273. return ~q, b + ~r
  274. else:
  275. return _divmod_pos(a, b)