Skip to content

Commit 16908fb

Browse files
committed
Avoid the quadratic behaviour inside _divmod_pos.
Code from Bjorn Martinsson.
1 parent 2298094 commit 16908fb

File tree

1 file changed

+43
-11
lines changed

1 file changed

+43
-11
lines changed

Lib/_pylong.py

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -213,21 +213,53 @@ def _div3n2n(a12, a3, b, b1, b2, n):
213213
return q, r
214214

215215

216+
def _int2digits(a, n):
217+
"""decompose non-negative integer a into base 2**n"""
218+
a_digits = [0] * ((a.bit_length() + n - 1) // n)
219+
220+
def inner(x, L, R):
221+
if L + 1 == R:
222+
a_digits[L] = x
223+
return
224+
mid = (L + R) >> 1
225+
shift = (mid - L) * n
226+
upper = x >> shift
227+
lower = x ^ (upper << shift)
228+
inner(lower, L, mid)
229+
inner(upper, mid, R)
230+
231+
if a:
232+
inner(a, 0, len(a_digits))
233+
return a_digits
234+
235+
236+
def _digits2int(digits, n):
237+
"""combine base-2**n digits into an int"""
238+
239+
def inner(L, R):
240+
if L + 1 == R:
241+
return digits[L]
242+
mid = (L + R) >> 1
243+
shift = (mid - L) * n
244+
return (inner(mid, R) << shift) + inner(L, mid)
245+
246+
return inner(0, len(digits)) if digits else 0
247+
248+
216249
def _divmod_pos(a, b):
217-
"""Divide a positive integer a by a positive integer b, giving
250+
"""Divide a non-negative integer a by a positive integer b, giving
218251
quotient and remainder."""
219252
# Use grade-school algorithm in base 2**n, n = nbits(b)
220253
n = b.bit_length()
221-
mask = (1 << n) - 1
222-
a_digits = []
223-
while a:
224-
a_digits.append(a & mask)
225-
a >>= n
226-
r = 0 if a_digits[-1] >= b else a_digits.pop()
227-
q = 0
228-
while a_digits:
229-
q_digit, r = _div2n1n((r << n) + a_digits.pop(), b, n)
230-
q = (q << n) + q_digit
254+
a_digits = _int2digits(a, n)
255+
256+
r = 0
257+
q_digits = []
258+
for a_digit in reversed(a_digits):
259+
q_digit, r = _div2n1n((r << n) + a_digit, b, n)
260+
q_digits.append(q_digit)
261+
q_digits.reverse()
262+
q = _digits2int(q_digits, n)
231263
return q, r
232264

233265

0 commit comments

Comments
 (0)