Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 877a212

Browse files
committed
Introduced helper functions v_iadd and v_isub, for in-place digit-vector
addition and subtraction. Reworked the tail end of k_mul() to use them. This saves oodles of one-shot longobject allocations (this is a triply- recursive routine, so saving one allocation in the body saves 3**n allocations at depth n; we actually save 2 allocations in the body).
1 parent e343878 commit 877a212

1 file changed

Lines changed: 75 additions & 29 deletions

File tree

Objects/longobject.c

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,57 @@ convert_binop(PyObject *v, PyObject *w, PyLongObject **a, PyLongObject **b) {
775775
return Py_NotImplemented; \
776776
}
777777

778+
/* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n]
779+
* is modified in place, by adding y to it. Carries are propagated as far as
780+
* x[m-1], and the remaining carry (0 or 1) is returned.
781+
*/
782+
static digit
783+
v_iadd(digit *x, int m, digit *y, int n)
784+
{
785+
int i;
786+
digit carry = 0;
787+
788+
assert(m >= n);
789+
for (i = 0; i < n; ++i) {
790+
carry += x[i] + y[i];
791+
x[i] = carry & MASK;
792+
carry >>= SHIFT;
793+
assert((carry & 1) == carry);
794+
}
795+
for (; carry && i < m; ++i) {
796+
carry += x[i];
797+
x[i] = carry & MASK;
798+
carry >>= SHIFT;
799+
assert((carry & 1) == carry);
800+
}
801+
return carry;
802+
}
803+
804+
/* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n]
805+
* is modified in place, by subtracting y from it. Borrows are propagated as
806+
* far as x[m-1], and the remaining borrow (0 or 1) is returned.
807+
*/
808+
static digit
809+
v_isub(digit *x, int m, digit *y, int n)
810+
{
811+
int i;
812+
digit borrow = 0;
813+
814+
assert(m >= n);
815+
for (i = 0; i < n; ++i) {
816+
borrow = x[i] - y[i] - borrow;
817+
x[i] = borrow & MASK;
818+
borrow >>= SHIFT;
819+
borrow &= 1; /* keep only 1 sign bit */
820+
}
821+
for (; borrow && i < m; ++i) {
822+
borrow = x[i] - borrow;
823+
x[i] = borrow & MASK;
824+
borrow >>= SHIFT;
825+
borrow &= 1;
826+
}
827+
return borrow;
828+
}
778829

779830
/* Multiply by a single digit, ignoring the sign. */
780831

@@ -1558,7 +1609,9 @@ k_mul(PyLongObject *a, PyLongObject *b)
15581609
PyLongObject *t1, *t2;
15591610
int shift; /* the number of digits we split off */
15601611
int i;
1561-
1612+
#ifdef Py_DEBUG
1613+
digit d;
1614+
#endif
15621615
/* (ah*X+al)(bh*X+bl) = ah*bh*X*X + (ah*bl + al*bh)*X + al*bl
15631616
* Let k = (ah+al)*(bh+bl) = ah*bl + al*bh + ah*bh + al*bl
15641617
* Then the original product is
@@ -1629,39 +1682,32 @@ k_mul(PyLongObject *a, PyLongObject *b)
16291682
Py_DECREF(t2);
16301683
if (k == NULL) goto fail;
16311684

1632-
/* Subtract ahbh and albl from k. Note that this can't become
1633-
* negative, since k = ahbh + albl + other stuff.
1634-
*/
1635-
if ((t1 = x_sub(k, ahbh)) == NULL) goto fail;
1685+
/* Add k into the result, starting at the shift'th LSD. */
1686+
i = ret->ob_size - shift; /* # digits after shift */
1687+
#ifdef Py_DEBUG
1688+
d =
1689+
#endif
1690+
v_iadd(ret->ob_digit + shift, i, k->ob_digit, k->ob_size);
1691+
assert(d == 0);
16361692
Py_DECREF(k);
1637-
k = t1;
1693+
1694+
/* Subtract ahbh and albl from the result. Note that this can't
1695+
* become negative, since k = ahbh + albl + other stuff.
1696+
*/
1697+
#ifdef Py_DEBUG
1698+
d =
1699+
#endif
1700+
v_isub(ret->ob_digit + shift, i, ahbh->ob_digit, ahbh->ob_size);
1701+
assert(d == 0);
16381702
Py_DECREF(ahbh);
1639-
ahbh = NULL;
16401703

1641-
if ((t1 = x_sub(k, albl)) == NULL) goto fail;
1642-
Py_DECREF(k);
1643-
k = t1;
1704+
#ifdef Py_DEBUG
1705+
d =
1706+
#endif
1707+
v_isub(ret->ob_digit + shift, i, albl->ob_digit, albl->ob_size);
1708+
assert(d == 0);
16441709
Py_DECREF(albl);
1645-
albl = NULL;
16461710

1647-
/* Add k into the result, at the shift-th least-significant digit. */
1648-
{
1649-
int j; /* index into k */
1650-
digit carry = 0;
1651-
1652-
for (i = shift, j = 0; j < k->ob_size; ++i, ++j) {
1653-
carry += ret->ob_digit[i] + k->ob_digit[j];
1654-
ret->ob_digit[i] = carry & MASK;
1655-
carry >>= SHIFT;
1656-
}
1657-
for (; carry && i < ret->ob_size; ++i) {
1658-
carry += ret->ob_digit[i];
1659-
ret->ob_digit[i] = carry & MASK;
1660-
carry >>= SHIFT;
1661-
}
1662-
assert(carry == 0);
1663-
}
1664-
Py_DECREF(k);
16651711
return long_normalize(ret);
16661712

16671713
fail:

0 commit comments

Comments
 (0)