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
15 changes: 15 additions & 0 deletions Lib/test/test_long.py
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,21 @@ class MyInt(int):
# GH-117195 -- This shouldn't crash
object.__sizeof__(1)

def test_long_add_overallocate(self):
# see gh-100687
x = (MASK//2) * (MASK+1)
x2 = (MASK//2 + 1) * (MASK+1)
z = x + x2
self.assertEqual(x + x2, MASK * (MASK + 1))

def test_karatsuba_single_digit_parts(self):
# gh-100687: k_mul() adds the halves of its operands with x_add(),
# and those halves can be single digits.
a = 1 + (1 << (SHIFT * 70))
b = 1 << (SHIFT * 139)
self.assertEqual(a * b, (1 << (SHIFT * 139)) + (1 << (SHIFT * 209)))
self.assertEqual(b * a, a * b)

def test_hash(self):
# gh-136599
self.assertEqual(hash(-1), -2)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Reduce frequency of overallocation in some cases of multidigit integer
additions and subtractions.
17 changes: 14 additions & 3 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3760,7 +3760,13 @@ x_add(PyLongObject *a, PyLongObject *b)
size_a = size_b;
size_b = size_temp; }
}
z = long_alloc(size_a+1);
assert(size_a >= 1);
/* A carry out of the top digit is only possible if the top digits sum
to at least PyLong_MASK; only then allocate a digit for it. */
digit top_sum = a->long_value.ob_digit[size_a - 1]
+ (size_b == size_a ? b->long_value.ob_digit[size_b - 1] : (digit)0);
int extra_digit = top_sum >= PyLong_MASK;
z = long_alloc(size_a + extra_digit);
if (z == NULL)
return NULL;
for (i = 0; i < size_b; ++i) {
Expand All @@ -3773,8 +3779,13 @@ x_add(PyLongObject *a, PyLongObject *b)
z->long_value.ob_digit[i] = carry & PyLong_MASK;
carry >>= PyLong_SHIFT;
}
z->long_value.ob_digit[i] = carry;
return long_normalize(z);
if (extra_digit) {
z->long_value.ob_digit[i] = carry;
return long_normalize(z);
}
assert(carry == 0);
assert(z->long_value.ob_digit[i - 1] != 0);
return z;
}

/* Subtract the absolute values of two integers. */
Expand Down
Loading