Skip to content

Commit 0d3ab6f

Browse files
XiaohongGongblurb-it[bot]StanFromIreland
authored
gh-156443: Keep PyLong loop carries as twodigits in shifts (#157060)
* gh-156443: Keep PyLong loop carries as twodigits in shifts and division * πŸ“œπŸ€– Added by blurb_it. * Update NEWS docs * Update NEWS.d doc * Update unit test and NEWS.d * Revert changes to x_divrem * Fix NEWS.d * Apply batched suggestions from code review Co-authored-by: Stan Ulbrych <stan@python.org> --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Stan Ulbrych <stan@python.org>
1 parent 44579b0 commit 0d3ab6f

3 files changed

Lines changed: 36 additions & 9 deletions

File tree

β€ŽLib/test/test_long.pyβ€Ž

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,33 @@ def test_division(self):
204204
self.check_division(710031681576388032, 26769404391308)
205205
self.check_division(1933622614268221, 30212853348836)
206206

207-
207+
@support.requires_IEEE_754
208+
def test_intradigit_shift(self):
209+
# Unit tests for v_lshift and v_rshift in longobject.c.
210+
# These two functions are not used by Python << and >>,
211+
# exercise them via float conversion and true division.
212+
213+
# Full limb values.
214+
two_limbs = (1 << (2 * SHIFT)) - 1
215+
three_limbs = (1 << (3 * SHIFT)) - 1
216+
four_limbs = (1 << (4 * SHIFT)) - 1
217+
# Multi-limb (not compact) but bit_length() still <= 55.
218+
bits50 = (1 << 50) - 1
219+
220+
# _PyLong_Frexp (float(n)):
221+
# v_lshift if n.bit_length() <= 55, else v_rshift.
222+
self.check_float_conversion(bits50)
223+
self.check_float_conversion(two_limbs)
224+
self.check_float_conversion(four_limbs)
225+
self.check_float_conversion(10**40)
226+
227+
# long_true_divide (a / b):
228+
# - (a.bit_length() - b.bit_length()) <= 55 => v_lshift,
229+
# - (a.bit_length() - b.bit_length()) > 55 => v_rshift.
230+
self.check_truediv(three_limbs, two_limbs)
231+
self.check_truediv(four_limbs, two_limbs)
232+
self.check_truediv(four_limbs, three_limbs)
233+
self.check_truediv(10**40, 10**20)
208234

209235
def test_karatsuba(self):
210236
digits = list(range(1, 5)) + list(range(KARATSUBA_CUTOFF,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Speed up :func:`float` conversion and true division of large :class:`int` values.

β€ŽObjects/longobject.cβ€Ž

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,15 +1905,15 @@ static digit
19051905
v_lshift(digit *z, digit *a, Py_ssize_t m, int d)
19061906
{
19071907
Py_ssize_t i;
1908-
digit carry = 0;
1908+
twodigits carry = 0;
19091909

19101910
assert(0 <= d && d < PyLong_SHIFT);
19111911
for (i=0; i < m; i++) {
19121912
twodigits acc = (twodigits)a[i] << d | carry;
19131913
z[i] = (digit)acc & PyLong_MASK;
1914-
carry = (digit)(acc >> PyLong_SHIFT);
1914+
carry = acc >> PyLong_SHIFT;
19151915
}
1916-
return carry;
1916+
return (digit)carry;
19171917
}
19181918

19191919
/* Shift digit vector a[0:m] d bits right, with 0 <= d < PyLong_SHIFT. Put
@@ -1923,16 +1923,16 @@ static digit
19231923
v_rshift(digit *z, digit *a, Py_ssize_t m, int d)
19241924
{
19251925
Py_ssize_t i;
1926-
digit carry = 0;
1927-
digit mask = ((digit)1 << d) - 1U;
1926+
twodigits carry = 0;
1927+
twodigits mask = ((twodigits)1 << d) - 1U;
19281928

19291929
assert(0 <= d && d < PyLong_SHIFT);
19301930
for (i=m; i-- > 0;) {
1931-
twodigits acc = (twodigits)carry << PyLong_SHIFT | a[i];
1932-
carry = (digit)acc & mask;
1931+
twodigits acc = carry << PyLong_SHIFT | a[i];
1932+
carry = acc & mask;
19331933
z[i] = (digit)(acc >> d);
19341934
}
1935-
return carry;
1935+
return (digit)carry;
19361936
}
19371937

19381938
/* Divide long pin, w/ size digits, by non-zero digit n, storing quotient

0 commit comments

Comments
Β (0)