Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
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.
27 changes: 24 additions & 3 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3387,16 +3387,29 @@ x_add(PyLongObject *a, PyLongObject *b)
Py_ssize_t i;
digit carry = 0;

/* There are fast paths for cases where a and b both have at most a single
digit, so if we end up here then at least one of them is multi-digit. */
assert(size_a >= 2 || size_b >= 2);

/* Ensure a is the larger of the two: */
if (size_a < size_b) {
{ PyLongObject *temp = a; a = b; b = temp; }
{ Py_ssize_t size_temp = size_a;
size_a = size_b;
size_b = size_temp; }
}
z = _PyLong_New(size_a+1);

/* Allocate sufficient space for the result. In the majority of cases
we allocate exactly the right number of digits, but in the (relatively
rare) case where the sum of the topmost digits is exactly PyLong_MASK,
we'll sometimes end up overallocating by a single digit. */
digit top_sum = a->ob_digit[size_a-1]
+ (size_b == size_a ? b->ob_digit[size_b-1] : (digit)0);
int extra_digit = top_sum >= PyLong_MASK;
z = _PyLong_New(size_a+extra_digit);
if (z == NULL)
return NULL;

for (i = 0; i < size_b; ++i) {
carry += a->ob_digit[i] + b->ob_digit[i];
z->ob_digit[i] = carry & PyLong_MASK;
Expand All @@ -3407,8 +3420,16 @@ x_add(PyLongObject *a, PyLongObject *b)
z->ob_digit[i] = carry & PyLong_MASK;
carry >>= PyLong_SHIFT;
}
z->ob_digit[i] = carry;
return long_normalize(z);
if (extra_digit) {
if (carry) {
z->ob_digit[i] = carry;
}
else {
/* rare case: we didn't need the extra digit after all */
Py_SET_SIZE(z, size_a);
}
}
return z;
}

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