Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion Lib/test/test_long.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,33 @@ def test_division(self):
self.check_division(710031681576388032, 26769404391308)
self.check_division(1933622614268221, 30212853348836)


@support.requires_IEEE_754
def test_intradigit_shift(self):
# Unit tests for v_lshift and v_rshift in longobject.c.
# These two functions are not used by Python << and >>,
# exercise them via float conversion and true division.

# Full limb values.
two_limbs = (1 << (2 * SHIFT)) - 1
three_limbs = (1 << (3 * SHIFT)) - 1
four_limbs = (1 << (4 * SHIFT)) - 1
# Multi-limb (not compact) but bit_length() still <= 55.
bits50 = (1 << 50) - 1

# _PyLong_Frexp (float(n)):
# v_lshift if n.bit_length() <= 55, else v_rshift.
self.check_float_conversion(bits50)
self.check_float_conversion(two_limbs)
self.check_float_conversion(four_limbs)
self.check_float_conversion(10**40)

# long_true_divide (a / b):
# - (a.bit_length() - b.bit_length()) <= 55 => v_lshift,
# - (a.bit_length() - b.bit_length()) > 55 => v_rshift.
self.check_truediv(three_limbs, two_limbs)
self.check_truediv(four_limbs, two_limbs)
self.check_truediv(four_limbs, three_limbs)
self.check_truediv(10**40, 10**20)

def test_karatsuba(self):
digits = list(range(1, 5)) + list(range(KARATSUBA_CUTOFF,
Expand Down
Comment thread
XiaohongGong marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Optimize shifts of large :class:`int` values.
16 changes: 8 additions & 8 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1905,15 +1905,15 @@ static digit
v_lshift(digit *z, digit *a, Py_ssize_t m, int d)
{
Py_ssize_t i;
digit carry = 0;
twodigits carry = 0;

assert(0 <= d && d < PyLong_SHIFT);
for (i=0; i < m; i++) {
twodigits acc = (twodigits)a[i] << d | carry;
z[i] = (digit)acc & PyLong_MASK;
carry = (digit)(acc >> PyLong_SHIFT);
carry = acc >> PyLong_SHIFT;
}
return carry;
return (digit)carry;
}

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

assert(0 <= d && d < PyLong_SHIFT);
for (i=m; i-- > 0;) {
twodigits acc = (twodigits)carry << PyLong_SHIFT | a[i];
carry = (digit)acc & mask;
twodigits acc = carry << PyLong_SHIFT | a[i];
carry = acc & mask;
z[i] = (digit)(acc >> d);
}
return carry;
return (digit)carry;
}

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