Index: longobject.c =================================================================== --- longobject.c (revision 70592) +++ longobject.c (working copy) @@ -16,6 +16,7 @@ #define NSMALLNEGINTS 5 #endif + /* convert a PyLong of size 1, 0 or -1 to an sdigit */ #define MEDIUM_VALUE(x) (Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \ (Py_SIZE(x) == 0 ? (sdigit)0 : \ @@ -1517,6 +1518,107 @@ Return a string object. If base is 2, 8 or 16, add the proper prefix '0b', '0o' or '0x'. */ +static void +_PyLong_Format_small(PyLongObject *a, int base, int power, digit powbase, + char *pp, PyLongObject *scratch, Py_ssize_t end) +{ + Py_ssize_t size, size_a = ABS(Py_SIZE(a)); + char *p = pp + end; + digit *pin = a->ob_digit; + size = size_a; + /* Repeatedly divide by powbase. */ + do { + int ntostore = power; + 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; + + /* Break rem into digits. */ + assert(ntostore > 0); + do { + digit nextrem = (digit)(rem / base); + char c = (char)(rem - nextrem * base); + assert(p > PyUnicode_AS_UNICODE(str)); + c += (c < 10) ? '0' : 'a'-10; + *--p = c; + rem = nextrem; + --ntostore; + /* Termination is a bit delicate: must not + store leading zeroes, so must get out if + remaining quotient and rem are both 0. */ + } while (ntostore && (size || rem)); + } while (size != 0); +} + +#define NUMERAL_SIZE 350 + +static PyObject * long_pow(PyObject *v, PyObject *w, PyObject *x); +static int l_divmod(PyLongObject *v, PyLongObject *w, + PyLongObject **pdiv, PyLongObject **pmod); +/* return -1 on failure, 0 for normal exit */ +static int +_numeral(PyLongObject *n, int base, PyObject* pbase, int power, digit powbase, + char *p, PyLongObject *scratch, Py_ssize_t end) +{ + digit msd; + int status, ad, bd; + Py_ssize_t size, half, ndigits, msd_bits = 0; + PyLongObject *div, *mod; + PyObject *phalf, *pbase_phalf; + /* compute the approximate number of digits in the given base; + * use code from bit_length + */ + ndigits = ABS(Py_SIZE(n)); + if(ndigits == 0) + return 0; + msd = n->ob_digit[ndigits-1]; + while (msd >= 32) { + msd_bits += 6; + msd >>= 6; + } + msd_bits += (long)(BitLengthTable[msd]); + size = (ndigits-1)*PyLong_SHIFT + msd_bits; + size = (Py_ssize_t)(size / log(base) + 1); + if(size < NUMERAL_SIZE){ + _PyLong_Format_small(n, base, power, powbase, p, + scratch, end); + return 0; + } + half = (size / 2) + (size & 1); + if((phalf = PyLong_FromLong(half)) == NULL) + return -1; + pbase_phalf = long_pow(pbase, phalf, Py_None); + if(!pbase_phalf){ + Py_DECREF(phalf); + return -1; + } + Py_DECREF(phalf); + status = l_divmod(n, (PyLongObject*)pbase_phalf, &div, &mod); + if(status < 0){ + Py_DECREF(pbase_phalf); + return -1; + } + Py_DECREF(pbase_phalf); + SIGCHECK({ + return -1; + }) + ad = _numeral(div, base, pbase, power, powbase, p, scratch, + end - half); + if(ad < 0){ + return -1; + } + bd = _numeral(mod, base, pbase, power, powbase, p, scratch, end); + if(bd < 0){ + Py_DECREF(div); + return -1; + } + Py_DECREF(div); + Py_DECREF(mod); + return 0; +} + PyObject * _PyLong_Format(PyObject *aa, int base) { @@ -1525,6 +1627,7 @@ Py_ssize_t i, j, sz; Py_ssize_t size_a; Py_UNICODE *p; + char *pc; int bits; char sign = '\0'; @@ -1609,39 +1712,83 @@ Py_DECREF(str); return NULL; } - + + if(sz < NUMERAL_SIZE){ /* Repeatedly divide by powbase. */ - do { - int ntostore = power; - 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({ + do { + int ntostore = power; + 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(scratch); + Py_DECREF(str); + return NULL; + }) + /* Break rem into digits. */ + assert(ntostore > 0); + do { + digit nextrem = (digit)(rem / base); + char c = (char)(rem - nextrem * base); + assert(p > PyUnicode_AS_UNICODE(str)); + c += (c < 10) ? '0' : 'a'-10; + *--p = c; + rem = nextrem; + --ntostore; + /* Termination is a bit delicate: must not + store leading zeroes, so must get out if + remaining quotient and rem are both 0. */ + } while (ntostore && (size || rem)); + } while (size != 0); + } + else { + int status, j=0; + Py_ssize_t len1; + PyObject *pbase; + if(!(pc = (char*) malloc(sz))){ Py_DECREF(scratch); Py_DECREF(str); return NULL; - }) - - /* Break rem into digits. */ - assert(ntostore > 0); - do { - digit nextrem = (digit)(rem / base); - char c = (char)(rem - nextrem * base); - assert(p > PyUnicode_AS_UNICODE(str)); - c += (c < 10) ? '0' : 'a'-10; - *--p = c; - rem = nextrem; - --ntostore; - /* Termination is a bit delicate: must not - store leading zeroes, so must get out if - remaining quotient and rem are both 0. */ - } while (ntostore && (size || rem)); - } while (size != 0); + } + for(i=0; i < sz; i++) + pc[i] = '0'; + if(!(pbase = PyLong_FromLong(base))){ + Py_DECREF(scratch); + Py_DECREF(str); + return NULL; + } + pc[sz] = '\0'; + if(sign == '-') + Py_SIZE(a) = -Py_SIZE(a); + status = _numeral(a, base, pbase, power, powbase, pc, scratch, sz); + if(sign == '-') + Py_SIZE(a) = -Py_SIZE(a); + Py_DECREF(pbase); + if (status < 0){ + Py_DECREF(scratch); + Py_DECREF(str); + return NULL; + } + + for(i=0; i < sz; i++){ + if (pc[i] > 48) + break; + } + + for(; i < sz; i++){ + pc[j++] = (pc[i] > 0)?pc[i]:'0'; + } + pc[j] = '\0'; + len1 = strlen(pc); + *p = '\0'; + for(i=len1-1; i >= 0; i--) + *--p = pc[i]; + free(pc); + } Py_DECREF(scratch); } - if (base == 16) { *--p = 'x'; *--p = '0';