[pypy-commit] pypy faster-str-of-bigint: kill the generic part of the previous _format and salvage the special case for

cfbolz noreply at buildbot.pypy.org
Wed Jun 26 09:10:31 CEST 2013


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: faster-str-of-bigint
Changeset: r64996:49cce796c701
Date: 2013-06-26 09:09 +0200
http://bitbucket.org/pypy/pypy/changeset/49cce796c701/

Log:	kill the generic part of the previous _format and salvage the
	special case for powers of two

diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -1979,10 +1979,7 @@
     Convert a bigint object to a string, using a given conversion base.
     Return a string object.
     """
-    size_a = a.numdigits()
 
-    base = len(digits)
-    assert base >= 2 and base <= 36
 
     # Compute a rough upper bound for the length of the string
     i = base
@@ -2002,8 +1999,15 @@
     if a.sign == 0:
         p -= 1
         s[p] = '0'
-    elif (base & (base - 1)) == 0:
+
+def _format_base2(a, digits, prefix, suffix):
         # JRH: special case for power-of-2 bases
+        output = StringBuilder()
+        if a.sign < 0:
+            output.append('-')
+        output.append(prefix)
+        base = len(digits)
+        size_a = a.numdigits()
         accum = 0
         accumbits = 0  # # of bits in accum
         basebits = 1   # # of bits in base-1
@@ -2019,11 +2023,10 @@
             accum |= a.widedigit(i) << accumbits
             accumbits += SHIFT
             assert accumbits >= basebits
+            out = []
             while 1:
                 cdigit = intmask(accum & (base - 1))
-                p -= 1
-                assert p >= 0
-                s[p] = digits[cdigit]
+                out.append(digits[cdigit])
                 accumbits -= basebits
                 accum >>= basebits
                 if i < size_a - 1:
@@ -2032,66 +2035,11 @@
                 else:
                     if accum <= 0:
                         break
-                        
+            out.reverse()
+            output.append("".join(out))
             i += 1
-    else:
-        # 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.
-        size = size_a
-        pin = a # just for similarity to C source which uses the array
-        # powbase <- largest power of base that fits in a digit.
-        powbase = _widen_digit(base)  # powbase == base ** power
-        power = 1
-        while 1:
-            newpow = powbase * base
-            if newpow >> SHIFT:  # doesn't fit in a digit
-                break
-            powbase = newpow
-            power += 1
-
-        # Get a scratch area for repeated division.
-        scratch = rbigint([NULLDIGIT] * size, 1, size)
-
-        # Repeatedly divide by powbase.
-        while 1:
-            ntostore = power
-            rem = _inplace_divrem1(scratch, pin, powbase, size)
-            pin = scratch  # no need to use a again
-            if pin._digits[size - 1] == NULLDIGIT:
-                size -= 1
-
-            # Break rem into digits.
-            assert ntostore > 0
-            while 1:
-                nextrem = rem // base
-                c = rem - nextrem * base
-                p -= 1
-                assert p >= 0
-                s[p] = digits[c]
-                rem = nextrem
-                ntostore -= 1
-                # Termination is a bit delicate:  must not
-                # store leading zeroes, so must get out if
-                # remaining quotient and rem are both 0.
-                if not (ntostore and (size or rem)):
-                    break
-            if size == 0:
-                break
-
-    j = len(prefix)
-    while j > 0:
-        p -= 1
-        j -= 1
-        s[p] = prefix[j]
-
-    if a.sign < 0:
-        p -= 1
-        s[p] = '-'
-
-    assert p >= 0    # otherwise, buffer overflow (this is also a
-                     # hint for the annotator for the slice below)
-    return ''.join(s[p:])
+        output.append(suffix)
+        return output.build()
 
 _FORMAT_MINDIGITS = 5 # 36 ** 5 fits in 32 bits, there may be a better choice for this
 
@@ -2130,6 +2078,9 @@
     if x.sign == 0:
         return prefix + "0" + suffix
     base = len(digits)
+    assert base >= 2 and base <= 36
+    if (base & (base - 1)) == 0:
+        return _format_base2(x, digits, prefix, suffix)
     negative = x.sign < 0
     if negative:
         x = x.neg()


More information about the pypy-commit mailing list