Author: stian
Branch: improve-rbigint
Changeset: r56318:fb9c7d03ec58
Date: 2012-06-22 23:37 +0200
http://bitbucket.org/pypy/pypy/changeset/fb9c7d03ec58/

Log:    Futher improvements, two more tests

diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -93,9 +93,7 @@
 class rbigint(object):
     """This is a reimplementation of longs using a list of digits."""
 
-    def __init__(self, digits=[], sign=0):
-        if len(digits) == 0:
-            digits = [NULLDIGIT]
+    def __init__(self, digits=[NULLDIGIT], sign=0):
         _check_digits(digits)
         make_sure_not_resized(digits)
         self._digits = digits
@@ -374,7 +372,7 @@
             result = _x_mul(self, other)
         result.sign = self.sign * other.sign
         return result
-
+    
     def truediv(self, other):
         div = _bigint_true_divide(self, other)
         return div
@@ -450,27 +448,29 @@
             if a.sign < 0:
                 a, temp = a.divmod(c)
                 a = temp
-
+                
+        size_b = b.numdigits()
+            
         # At this point a, b, and c are guaranteed non-negative UNLESS
         # c is NULL, in which case a may be negative. */
 
-        z = rbigint([_store_digit(1)], 1)
-
+        z = rbigint([ONEDIGIT], 1)
+        
         # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result)
         # into helper function result = _help_mult(x, y, c)
-        if b.numdigits() <= FIVEARY_CUTOFF:
+        if not c or size_b <= FIVEARY_CUTOFF:
             # Left-to-right binary exponentiation (HAC Algorithm 14.79)
             # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
-            i = b.numdigits() - 1
-            while i >= 0:
-                bi = b.digit(i)
+            size_b -= 1
+            while size_b >= 0:
+                bi = b.digit(size_b)
                 j = 1 << (SHIFT-1)
                 while j != 0:
                     z = _help_mult(z, z, c)
                     if bi & j:
                         z = _help_mult(z, a, c)
                     j >>= 1
-                i -= 1
+                size_b -= 1
         else:
             # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82)
             # This is only useful in the case where c != None.
@@ -479,7 +479,7 @@
             table[0] = z
             for i in range(1, 32):
                 table[i] = _help_mult(table[i-1], a, c)
-            i = b.numdigits()
+
             # Note that here SHIFT is not a multiple of 5.  The difficulty
             # is to extract 5 bits at a time from 'b', starting from the
             # most significant digits, so that at the end of the algorithm
@@ -488,11 +488,11 @@
             # m+ = m rounded up to the next multiple of 5
             # j  = (m+) % SHIFT = (m+) - (i * SHIFT)
             # (computed without doing "i * SHIFT", which might overflow)
-            j = i % 5
+            j = size_b % 5
             if j != 0:
                 j = 5 - j
             if not we_are_translated():
-                assert j == (i*SHIFT+4)//5*5 - i*SHIFT
+                assert j == (size_b*SHIFT+4)//5*5 - size_b*SHIFT
             #
             accum = r_uint(0)
             while True:
@@ -502,10 +502,12 @@
                 else:
                     # 'accum' does not have enough digit.
                     # must get the next digit from 'b' in order to complete
-                    i -= 1
-                    if i < 0:
-                        break    # done
-                    bi = b.udigit(i)
+                    if size_b == 0:
+                        break # Done
+                        
+                    size_b -= 1
+
+                    bi = b.udigit(size_b)
                     index = ((accum << (-j)) | (bi >> (j+SHIFT))) & 0x1f
                     accum = bi
                     j += SHIFT
@@ -563,13 +565,11 @@
 
     def lqshift(self, int_other):
         " A quicker one with much less checks, int_other is valid and for the 
most part constant."
-        if int_other == 0:
-            return self
+        assert int_other > 0
 
         oldsize = self.numdigits()
-        newsize = oldsize + 1
 
-        z = rbigint([NULLDIGIT] * newsize, self.sign)
+        z = rbigint([NULLDIGIT] * (oldsize + 1), self.sign)
         accum = _widen_digit(0)
 
         for i in range(oldsize):
@@ -577,7 +577,7 @@
             z.setdigit(i, accum)
             accum >>= SHIFT
             
-        z.setdigit(newsize - 1, accum)
+        z.setdigit(oldsize, accum)
         z._normalize()
         return z
     
@@ -701,12 +701,10 @@
     # Perform a modular reduction, X = X % c, but leave X alone if c
     # is NULL.
     if c is not None:
-        res, temp = res.divmod(c)
-        res = temp
+        temp, res = res.divmod(c)
+        
     return res
 
-
-
 def digits_from_nonneg_long(l):
     digits = []
     while True:
@@ -850,21 +848,21 @@
     ptwotable[2 << x] = x+1
     ptwotable[-2 << x] = x+1
     
-def _x_mul(a, b):
+def _x_mul(a, b, digit=0):
     """
     Grade school multiplication, ignoring the signs.
     Returns the absolute value of the product, or None if error.
     """
 
     size_a = a.numdigits()
-    
+
     if size_a == 1:
         # Special case.
         digit = a.digit(0)
         if digit == 0:
             return rbigint([NULLDIGIT], 1)
         elif digit == 1:
-            return rbigint(b._digits[:], 1)
+            return rbigint(b._digits[:], 1) # We assume b was normalized 
already.
         
     size_b = b.numdigits()
 
@@ -909,33 +907,31 @@
             i += 1
         z._normalize()
         return z
-    else:
-        if size_a == 1:
-            digit = a.digit(0)
-            if digit & (digit - 1) == 0:
-                return b.lqshift(ptwotable[digit])
-        
-        z = rbigint([NULLDIGIT] * (size_a + size_b), 1)
-        # gradeschool long mult
-        i = 0
-        while i < size_a:
-            carry = 0
-            f = a.widedigit(i)
-            pz = i
-            pb = 0
-            while pb < size_b:
-                carry += z.widedigit(pz) + b.widedigit(pb) * f
-                pb += 1
-                z.setdigit(pz, carry)
-                pz += 1
-                carry >>= SHIFT
-                assert carry <= MASK
-            if carry:
-                z.setdigit(pz, z.widedigit(pz) + carry)
-            assert (carry >> SHIFT) == 0
-            i += 1
-        z._normalize()
-        return z
+    
+    elif digit and digit & (digit - 1) == 0:
+        return b.lqshift(ptwotable[digit])
+
+    z = rbigint([NULLDIGIT] * (size_a + size_b), 1)
+    # gradeschool long mult
+    i = 0
+    while i < size_a:
+        carry = 0
+        f = a.widedigit(i)
+        pz = i
+        pb = 0
+        while pb < size_b:
+            carry += z.widedigit(pz) + b.widedigit(pb) * f
+            pb += 1
+            z.setdigit(pz, carry)
+            pz += 1
+            carry >>= SHIFT
+            assert carry <= MASK
+        if carry:
+            z.setdigit(pz, z.widedigit(pz) + carry)
+        assert (carry >> SHIFT) == 0
+        i += 1
+    z._normalize()
+    return z
 
 
 def _kmul_split(n, size):
@@ -1140,7 +1136,8 @@
     # Successive slices of b are copied into bslice.
     #bslice = rbigint([0] * asize, 1)
     # XXX we cannot pre-allocate, see comments below!
-    bslice = rbigint([NULLDIGIT], 1)
+    # XXX prevent one list from being created.
+    bslice = rbigint(sign = 1)
     
     nbdone = 0;
     while bsize > 0:
diff --git a/pypy/translator/goal/targetbigintbenchmark.py 
b/pypy/translator/goal/targetbigintbenchmark.py
--- a/pypy/translator/goal/targetbigintbenchmark.py
+++ b/pypy/translator/goal/targetbigintbenchmark.py
@@ -10,6 +10,7 @@
     """
         A cutout with some benchmarks.
         Pypy default:
+        <No run yet>
         18.270045
         2.512140
         14.148920
@@ -17,13 +18,23 @@
         6.647562
 
         Pypy with improvements:
-        15.211410
-        1.707288
-        13.955348
-        14.474590
-        6.446812
+        6.048997
+        10.091559
+        14.680590
+        1.635417
+        12.023154
+        14.320596
+        6.464143
 
     """
+
+    t = time()
+    num = rbigint.pow(rbigint.fromint(10000), rbigint.fromint(2 ** 8))
+    for n in xrange(60000):
+        rbigint.pow(rbigint.fromint(10**4), num, rbigint.fromint(100))
+        
+
+    print time() - t
     
     t = time()
     i = rbigint.fromint(2**31)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to