]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Two patches by Jason Harper:
authorGuido van Rossum <guido@python.org>
Tue, 11 Aug 1998 15:04:47 +0000 (15:04 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 11 Aug 1998 15:04:47 +0000 (15:04 +0000)
- Faster conversion to string for binary bases: linear instead of quadratic!

- Allocate smaller result for certain masking ops, e.g. (1L<<30000) & 1.

Objects/longobject.c

index a6be3d9236b486b1abdc15713b1be478bc0ee241..992e7692192f9f7037b3c1f1bad5b1f0db3f0793 100644 (file)
@@ -315,9 +315,11 @@ PyLong_FromLongLong(ival)
 #else
        if( ival <= (long long)LONG_MAX ) {
                return PyLong_FromLong( (long)ival );
-       } else if( ival <= (unsigned long long)ULONG_MAX ) {
+       }
+       else if( ival <= (unsigned long long)ULONG_MAX ) {
                return PyLong_FromUnsignedLong( (unsigned long)ival );
-       } else {
+       }
+       else {
                /* Assume a C long long fits in at most 10 'digits'.
                 * Should be OK if we're assuming long fits in 5.
                 */
@@ -359,7 +361,8 @@ PyLong_FromUnsignedLongLong(ival)
 #else
        if( ival <= (unsigned long long)ULONG_MAX ) {
                return PyLong_FromUnsignedLong( (unsigned long)ival );
-       } else {
+       }
+       else {
                /* Assume a C long fits in at most 10 'digits'. */
                PyLongObject *v = _PyLong_New(10);
 
@@ -572,30 +575,71 @@ long_format(aa, base)
        if (a->ob_size < 0)
                sign = '-';
        
-       Py_INCREF(a);
-       do {
-               digit rem;
-               PyLongObject *temp = divrem1(a, (digit)base, &rem);
-               if (temp == NULL) {
-                       Py_DECREF(a);
-                       Py_DECREF(str);
-                       return NULL;
+       if (a->ob_size == 0) {
+               *--p = '0';
+       }
+       else if ((base & (base - 1)) == 0) {
+               /* JRH: special case for power-of-2 bases */
+               twodigits temp = a->ob_digit[0];
+               int bitsleft = SHIFT;
+               int rem;
+               int last = abs(a->ob_size);
+               int basebits = 1;
+               i = base;
+               while ((i >>= 1) > 1) ++basebits;
+               
+               i = 0;
+               for (;;) {
+                       while (bitsleft >= basebits) {
+                               if ((temp == 0) && (i >= last - 1)) break;
+                               rem = temp & (base - 1);
+                               if (rem < 10)
+                                       rem += '0';
+                               else
+                                       rem += 'A' - 10;
+                               assert(p > PyString_AS_STRING(str));
+                               *--p = (char) rem;
+                               bitsleft -= basebits;
+                               temp >>= basebits;
+                       }
+                       if (++i >= last) {
+                               if (temp == 0) break;
+                               bitsleft = 99;
+                               /* loop again to pick up final digits */
+                       }
+                       else {
+                               temp = (a->ob_digit[i] << bitsleft) | temp;
+                               bitsleft += SHIFT;
+                       }
                }
-               if (rem < 10)
-                       rem += '0';
-               else
-                       rem += 'A'-10;
-               assert(p > PyString_AS_STRING(str));
-               *--p = (char) rem;
-               Py_DECREF(a);
-               a = temp;
-               SIGCHECK({
+       }
+       else {
+               Py_INCREF(a);
+               do {
+                       digit rem;
+                       PyLongObject *temp = divrem1(a, (digit)base, &rem);
+                       if (temp == NULL) {
+                               Py_DECREF(a);
+                               Py_DECREF(str);
+                               return NULL;
+                       }
+                       if (rem < 10)
+                               rem += '0';
+                       else
+                               rem += 'A'-10;
+                       assert(p > PyString_AS_STRING(str));
+                       *--p = (char) rem;
                        Py_DECREF(a);
-                       Py_DECREF(str);
-                       return NULL;
-               })
-       } while (ABS(a->ob_size) != 0);
-       Py_DECREF(a);
+                       a = temp;
+                       SIGCHECK({
+                               Py_DECREF(a);
+                               Py_DECREF(str);
+                               return NULL;
+                       })
+               } while (ABS(a->ob_size) != 0);
+               Py_DECREF(a);
+       }
+
        if (base == 8) {
                if (size_a != 0)
                        *--p = '0';
@@ -723,7 +767,8 @@ long_divrem(a, b, pdiv, prem)
        PyLongObject *z;
        
        if (size_b == 0) {
-               PyErr_SetString(PyExc_ZeroDivisionError, "long division or modulo");
+               PyErr_SetString(PyExc_ZeroDivisionError,
+                               "long division or modulo");
                return -1;
        }
        if (size_a < size_b ||
@@ -1520,17 +1565,6 @@ long_bitwise(a, op, b)
                maskb = 0;
        }
        
-       size_a = a->ob_size;
-       size_b = b->ob_size;
-       size_z = MAX(size_a, size_b);
-       z = _PyLong_New(size_z);
-       if (a == NULL || b == NULL || z == NULL) {
-               Py_XDECREF(a);
-               Py_XDECREF(b);
-               Py_XDECREF(z);
-               return NULL;
-       }
-       
        negz = 0;
        switch (op) {
        case '^':
@@ -1557,6 +1591,31 @@ long_bitwise(a, op, b)
                break;
        }
        
+       /* JRH: The original logic here was to allocate the result value (z)
+          as the longer of the two operands.  However, there are some cases
+          where the result is guaranteed to be shorter than that: AND of two
+          positives, OR of two negatives: use the shorter number.  AND with
+          mixed signs: use the positive number.  OR with mixed signs: use the
+          negative number.  After the transformations above, op will be '&'
+          iff one of these cases applies, and mask will be non-0 for operands
+          whose length should be ignored.
+       */
+
+       size_a = a->ob_size;
+       size_b = b->ob_size;
+       size_z = op == '&'
+               ? (maska
+                  ? size_b
+                  : (maskb ? size_a : MIN(size_a, size_b)))
+               : MAX(size_a, size_b);
+       z = _PyLong_New(size_z);
+       if (a == NULL || b == NULL || z == NULL) {
+               Py_XDECREF(a);
+               Py_XDECREF(b);
+               Py_XDECREF(z);
+               return NULL;
+       }
+       
        for (i = 0; i < size_z; ++i) {
                diga = (i < size_a ? a->ob_digit[i] : 0) ^ maska;
                digb = (i < size_b ? b->ob_digit[i] : 0) ^ maskb;