[pypy-commit] pypy improve-rbigint: Add speedup for all (power of two)**num.

stian noreply at buildbot.pypy.org
Sat Jul 21 18:41:12 CEST 2012


Author: stian
Branch: improve-rbigint
Changeset: r56325:2e062df94210
Date: 2012-06-24 21:49 +0200
http://bitbucket.org/pypy/pypy/changeset/2e062df94210/

Log:	Add speedup for all (power of two)**num.

	One of the tests ((2**31)**(2**31)) is now 100 times faster (this
	beats CPython, and even C)

diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -8,7 +8,7 @@
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rpython import extregistry
 
-import math, sys
+import math, sys, array
 
 # note about digit sizes:
 # In division, the native integer type must be able to hold
@@ -459,7 +459,9 @@
                     "cannot be negative when 3rd argument specified")
             # XXX failed to implement
             raise ValueError("bigint pow() too negative")
-
+        
+        size_b = b.numdigits()
+        
         if c is not None:
             if c.sign == 0:
                 raise ValueError("pow() 3rd argument cannot be 0")
@@ -483,9 +485,8 @@
                 a, temp = a.divmod(c)
                 a = temp
                 
-        size_b = b.numdigits()
-        
-        if not c and size_b == 1 and a.sign == 1:
+            
+        elif size_b == 1 and a.sign == 1:
             digit = b.digit(0)
             if digit == 0:
                 return rbigint([ONEDIGIT], 1)
@@ -495,8 +496,8 @@
                 adigit = a.digit(0)
                 if adigit == 1:
                     return rbigint([ONEDIGIT], 1)
-                elif adigit == 2:
-                    return a.lshift(digit-1)
+                elif adigit & (adigit - 1) == 0:
+                    return a.lshift(((digit-1)*(ptwotable[adigit]-1)) + digit-1)
                 
         # At this point a, b, and c are guaranteed non-negative UNLESS
         # c is NULL, in which case a may be negative. */
@@ -518,6 +519,7 @@
                         z = _help_mult(z, a, c)
                     j >>= 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.
diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py
--- a/pypy/rlib/test/test_rbigint.py
+++ b/pypy/rlib/test/test_rbigint.py
@@ -1,6 +1,6 @@
 from __future__ import division
 import py
-import operator, sys
+import operator, sys, array
 from random import random, randint, sample
 from pypy.rlib.rbigint import rbigint, SHIFT, MASK, KARATSUBA_CUTOFF
 from pypy.rlib.rbigint import _store_digit
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
@@ -20,25 +20,34 @@
         6.647562
 
         Pypy with improvements:
-        9.474363
-        5.797121
-        10.068798
-        14.770187
-        1.620009
-        12.054951
-        14.292367
-        6.440351
+        9.451896
+        1.122038
+        5.787821
+        9.937016
+        14.927304
+        0.016683
+        12.018289
+        14.261727
+        6.434917
 
     """
     
-    t = time()
+    """t = time()
     num = rbigint.fromint(10000000)
     for n in xrange(10000):
         rbigint.pow(rbigint.fromint(2), num)
         
 
+    print time() - t"""
+
+    t = time()
+    num = rbigint.fromint(100000000)
+    for n in xrange(31):
+        rbigint.pow(rbigint.pow(rbigint.fromint(2), rbigint.fromint(n)), num)
+        
+
     print time() - t
-
+    
     t = time()
     num = rbigint.pow(rbigint.fromint(10000), rbigint.fromint(2 ** 8))
     for n in xrange(60000):


More information about the pypy-commit mailing list