summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-07-14 12:23:19 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-07-14 12:23:19 (GMT)
commit212e614f604af14465bde8a8d5a7419b0924be7f (patch)
tree2fbad07a115b673d500bc4a662e01e57ca89c286
parentc8a6b9b6d67c4bf343f3771fcae0002160066fe3 (diff)
downloadcpython-212e614f604af14465bde8a8d5a7419b0924be7f.zip
cpython-212e614f604af14465bde8a8d5a7419b0924be7f.tar.gz
cpython-212e614f604af14465bde8a8d5a7419b0924be7f.tar.bz2
divrem1 & long_format: found a clean way to factor divrem1 so that
long_format can reuse a scratch area for its repeated divisions (instead of malloc/free for every digit produced); speeds str(long)/repr(long).
-rw-r--r--Objects/longobject.c82
1 files changed, 54 insertions, 28 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index b9cc924..ad13b07 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -15,7 +15,7 @@
static PyLongObject *long_normalize(PyLongObject *);
static PyLongObject *mul1(PyLongObject *, wdigit);
static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit);
-static PyLongObject *divrem1(PyLongObject *, wdigit, digit *);
+static PyLongObject *divrem1(PyLongObject *, digit, digit *);
static PyObject *long_format(PyObject *aa, int base, int addL);
static int ticker; /* XXX Could be shared with ceval? */
@@ -707,28 +707,44 @@ muladd1(PyLongObject *a, wdigit n, wdigit extra)
return long_normalize(z);
}
+/* Divide long pin, w/ size digits, by non-zero digit n, storing quotient
+ in pout, and returning the remainder. pin and pout point at the LSD.
+ It's OK for pin == pout on entry, which saves oodles of mallocs/frees in
+ long_format, but that should be done with great care since longs are
+ immutable. */
+
+static digit
+inplace_divrem1(digit *pout, digit *pin, int size, digit n)
+{
+ twodigits rem = 0;
+
+ assert(n > 0 && n <= MASK);
+ pin += size;
+ pout += size;
+ while (--size >= 0) {
+ digit hi;
+ rem = (rem << SHIFT) + *--pin;
+ *--pout = hi = (digit)(rem / n);
+ rem -= hi * n;
+ }
+ return (digit)rem;
+}
+
/* Divide a long integer by a digit, returning both the quotient
(as function result) and the remainder (through *prem).
The sign of a is ignored; n should not be zero. */
static PyLongObject *
-divrem1(PyLongObject *a, wdigit n, digit *prem)
+divrem1(PyLongObject *a, digit n, digit *prem)
{
- int size = ABS(a->ob_size);
+ const int size = ABS(a->ob_size);
PyLongObject *z;
- int i;
- twodigits rem = 0;
assert(n > 0 && n <= MASK);
z = _PyLong_New(size);
if (z == NULL)
return NULL;
- for (i = size; --i >= 0; ) {
- rem = (rem << SHIFT) + a->ob_digit[i];
- z->ob_digit[i] = (digit) (rem/n);
- rem %= n;
- }
- *prem = (digit) rem;
+ *prem = inplace_divrem1(z->ob_digit, a->ob_digit, size, n);
return long_normalize(z);
}
@@ -742,7 +758,7 @@ long_format(PyObject *aa, int base, int addL)
register PyLongObject *a = (PyLongObject *)aa;
PyStringObject *str;
int i;
- int size_a = ABS(a->ob_size);
+ const int size_a = ABS(a->ob_size);
char *p;
int bits;
char sign = '\0';
@@ -779,7 +795,7 @@ long_format(PyObject *aa, int base, int addL)
twodigits temp = a->ob_digit[0];
int bitsleft = SHIFT;
int rem;
- int last = abs(a->ob_size);
+ int last = size_a;
int basebits = 1;
i = base;
while ((i >>= 1) > 1)
@@ -814,6 +830,10 @@ long_format(PyObject *aa, int base, int addL)
/* Not 0, and base not a power of 2. Divide repeatedly by
base, but for speed use the highest power of base that
fits in a digit. */
+ int size = size_a;
+ digit *pin = a->ob_digit;
+ PyLongObject *scratch;
+ /* powbasw <- largest power of base that fits in a digit. */
digit powbase = base; /* powbase == base ** power */
int power = 1;
for (;;) {
@@ -823,23 +843,29 @@ long_format(PyObject *aa, int base, int addL)
powbase = (digit)newpow;
++power;
}
-
- Py_INCREF(a);
+
+ /* Get a scratch area for repeated division. */
+ scratch = _PyLong_New(size);
+ if (scratch == NULL) {
+ Py_DECREF(str);
+ return NULL;
+ }
+
+ /* Repeatedly divide by powbase. */
do {
int ntostore = power;
- digit rem;
- PyLongObject *temp = divrem1(a, powbase, &rem);
- Py_DECREF(a);
- if (temp == NULL) {
- Py_DECREF(str);
- return NULL;
- }
- a = temp;
+ digit rem = inplace_divrem1(scratch->ob_digit,
+ pin, size, powbase);
+ pin = scratch->ob_digit; /* no need to use a again */
+ if (pin[size - 1] == 0)
+ --size;
SIGCHECK({
- Py_DECREF(a);
+ Py_DECREF(scratch);
Py_DECREF(str);
return NULL;
})
+
+ /* Break rem into digits. */
assert(ntostore > 0);
do {
digit nextrem = (digit)(rem / base);
@@ -851,10 +877,10 @@ long_format(PyObject *aa, int base, int addL)
--ntostore;
/* Termination is a bit delicate: must not
store leading zeroes, so must get out if
- a and rem are both 0 now. */
- } while (ntostore && (a->ob_size || rem));
- } while (a->ob_size != 0);
- Py_DECREF(a);
+ remaining quotient and rem are both 0. */
+ } while (ntostore && (size || rem));
+ } while (size != 0);
+ Py_DECREF(scratch);
}
if (base == 8) {