summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-06-14 04:56:19 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-06-14 04:56:19 (GMT)
commitce9de2f79a8676d6838e446cc72a9ab0a7b6cded (patch)
treef571266bc6a330add10799f7d0a03ab67bdab59b
parentff70d3c8d43b3ddcd4271b662dc0a029b22bd51a (diff)
downloadcpython-ce9de2f79a8676d6838e446cc72a9ab0a7b6cded.zip
cpython-ce9de2f79a8676d6838e446cc72a9ab0a7b6cded.tar.gz
cpython-ce9de2f79a8676d6838e446cc72a9ab0a7b6cded.tar.bz2
PyLong_From{Unsigned,}Long: count the # of digits first, so no more space
is allocated than needed (used to allocate 80 bytes of digit space no matter how small the long input). This also runs faster, at least on 32- bit boxes.
-rw-r--r--Objects/longobject.c62
1 files changed, 41 insertions, 21 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 93044ee..54d59c3 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -57,21 +57,34 @@ _PyLong_New(int size)
PyObject *
PyLong_FromLong(long ival)
{
- /* Assume a C long fits in at most 5 'digits' */
- /* Works on both 32- and 64-bit machines */
- PyLongObject *v = _PyLong_New(5);
+ PyLongObject *v;
+ unsigned long t; /* unsigned so >> doesn't propagate sign bit */
+ int ndigits = 0;
+ int negative = 0;
+
+ if (ival < 0) {
+ ival = -ival;
+ negative = 1;
+ }
+
+ /* Count the number of Python digits.
+ We used to pick 5 ("big enough for anything"), but that's a
+ waste of time and space given that 5*15 = 75 bits are rarely
+ needed. */
+ t = (unsigned long)ival;
+ while (t) {
+ ++ndigits;
+ t >>= SHIFT;
+ }
+ v = _PyLong_New(ndigits);
if (v != NULL) {
- unsigned long t = ival;
- int i;
- if (ival < 0) {
- t = -ival;
- v->ob_size = -(v->ob_size);
- }
- for (i = 0; i < 5; i++) {
- v->ob_digit[i] = (digit) (t & MASK);
+ digit *p = v->ob_digit;
+ v->ob_size = negative ? -ndigits : ndigits;
+ t = (unsigned long)ival;
+ while (t) {
+ *p++ = (digit)(t & MASK);
t >>= SHIFT;
}
- v = long_normalize(v);
}
return (PyObject *)v;
}
@@ -81,17 +94,24 @@ PyLong_FromLong(long ival)
PyObject *
PyLong_FromUnsignedLong(unsigned long ival)
{
- /* Assume a C long fits in at most 5 'digits' */
- /* Works on both 32- and 64-bit machines */
- PyLongObject *v = _PyLong_New(5);
+ PyLongObject *v;
+ unsigned long t;
+ int ndigits = 0;
+
+ /* Count the number of Python digits. */
+ t = (unsigned long)ival;
+ while (t) {
+ ++ndigits;
+ t >>= SHIFT;
+ }
+ v = _PyLong_New(ndigits);
if (v != NULL) {
- unsigned long t = ival;
- int i;
- for (i = 0; i < 5; i++) {
- v->ob_digit[i] = (digit) (t & MASK);
- t >>= SHIFT;
+ digit *p = v->ob_digit;
+ v->ob_size = ndigits;
+ while (ival) {
+ *p++ = (digit)(ival & MASK);
+ ival >>= SHIFT;
}
- v = long_normalize(v);
}
return (PyObject *)v;
}