[pypy-commit] pypy improve-rbigint: Working, but ineffective toom cook implantation

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


Author: stian
Branch: improve-rbigint
Changeset: r56354:62831f97a2c7
Date: 2012-07-07 00:50 +0200
http://bitbucket.org/pypy/pypy/changeset/62831f97a2c7/

Log:	Working, but ineffective toom cook implantation

diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -69,8 +69,8 @@
     
 KARATSUBA_SQUARE_CUTOFF = 2 * KARATSUBA_CUTOFF
 
-USE_TOOMCOCK = False # WIP
-TOOMCOOK_CUTOFF = 3 # Smallest possible cutoff is 3. Ideal is probably around 150+
+USE_TOOMCOCK = False
+TOOMCOOK_CUTOFF = 2000 # Smallest possible cutoff is 3. Ideal is probably around 150+
 
 # For exponentiation, use the binary left-to-right algorithm
 # unless the exponent contains more than FIVEARY_CUTOFF digits.
@@ -1127,6 +1127,7 @@
     hi._normalize()
     return hi, mid, lo
 
+THREERBIGINT = rbigint.fromint(3) # Used by tc_mul
 def _tc_mul(a, b):
     """
     Toom Cook
@@ -1145,11 +1146,6 @@
         bl = al
     else:
         bh, bm, bl = _tcmul_split(b, shift)
-
-    
-    # 1. Allocate result space.
-    ret = rbigint([NULLDIGIT] * (asize + bsize), 1)
-
     # 2. ahl, bhl
     ahl = al.add(ah)
     bhl = bl.add(bh)
@@ -1159,12 +1155,15 @@
     v1 = ahl.add(bm).mul(bhl.add(bm))
     
     vn1 = ahl.sub(bm).mul(bhl.sub(bm))
-    v2 = al.add(am.lshift(1)).add(ah.lshift(2)).mul(bl.add(bm.lshift(1))).add(bh.lshift(2))
+    v2 = al.add(am.lshift(1)).add(ah.lshift(2)).mul(bl.add(bm.lshift(1)).add(bh.lshift(2)))
     vinf = ah.mul(bh)
     
     # Construct
-    t1 = v0.mul(rbigint.fromint(3)).add(vn1.lshift(1)).add(v2).floordiv(rbigint.fromint(6)).sub(vinf.lshift(1))
-    t2 = v1.add(vn1).rshift(1)
+    t1 = v0.mul(THREERBIGINT).add(vn1.lshift(1)).add(v2)
+    _inplace_divrem1(t1, t1, 6)
+    t1 = t1.sub(vinf.lshift(1))
+    t2 = v1.add(vn1)
+    _v_rshift(t2, t2, t2.numdigits(), 1)
     
     r1 = v1.sub(t1)
     r2 = t2.sub(v0).sub(vinf)
@@ -1172,24 +1171,29 @@
     # r0 = v0, r4 = vinf
     
     # Now we fit r+ r2 + r4 into the new string.
-    # Now we got to add the r1 and r3 in the mid shift. This is TODO (aga, not fixed yet)
+    # Now we got to add the r1 and r3 in the mid shift.
+    # Allocate result space.
+    ret = rbigint([NULLDIGIT] * (4*shift + vinf.numdigits()), 1)  # This is because of the size of vinf
+    
     ret._digits[:v0.numdigits()] = v0._digits
-    
+    #print ret.numdigits(), r2.numdigits(), vinf.numdigits(), shift, shift * 5, asize, bsize
+    #print r2.sign >= 0
+    assert r2.sign >= 0
+    #print 2*shift + r2.numdigits() < ret.numdigits()
+    assert 2*shift + r2.numdigits() < ret.numdigits()
     ret._digits[shift * 2:shift * 2+r2.numdigits()] = r2._digits
-    
+    #print vinf.sign >= 0
+    assert vinf.sign >= 0
+    #print 4*shift + vinf.numdigits() <= ret.numdigits()
+    assert 4*shift + vinf.numdigits() <= ret.numdigits()
     ret._digits[shift*4:shift*4+vinf.numdigits()] = vinf._digits
 
-    # TODO!!!!
-    """
-    x and y are rbigints, m >= n required.  x.digits[0:n] is modified in place,
-    by adding y.digits[0:m] to it.  Carries are propagated as far as
-    x[m-1], and the remaining carry (0 or 1) is returned.
-    Python adaptation: x is addressed relative to xofs!
-    """
-    _v_iadd(ret, shift, ret.numdigits() - shift * 4, r1, r1.numdigits())
-    _v_iadd(ret, shift * 3, ret.numdigits() - shift * 4 , r3, r3.numdigits())
 
-    ret._normalize()
+    i = ret.numdigits() - shift
+    _v_iadd(ret, shift, i, r1, r1.numdigits())
+    _v_iadd(ret, shift * 3, i, r3, r3.numdigits())
+
+    ret._positivenormalize()
     return ret
 
 
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
@@ -459,6 +459,7 @@
     def test_tc_mul(self):
         a = rbigint.fromlong(1<<300)
         b = rbigint.fromlong(1<<200)
+        print _tc_mul(a, b)
         assert _tc_mul(a, b).tolong() == ((1<<300)*(1<<200))
         
     def test_overzelous_assertion(self):
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
@@ -64,6 +64,19 @@
     """
     sumTime = 0.0
     
+    
+    t = time()
+    by = rbigint.pow(rbigint.fromint(63), rbigint.fromint(100))
+    for n in xrange(9900):
+        by2 = by.lshift(63)
+        rbigint.mul(by, by2)
+        by = by2
+        
+
+    _time = time() - t
+    sumTime += _time
+    print "Toom-cook effectivity 100-10000 digits:", _time
+    
     t = time()
     num = rbigint.pow(rbigint.fromint(100000000), rbigint.fromint(1024))
     by = rbigint.pow(rbigint.fromint(2), rbigint.fromint(128))


More information about the pypy-commit mailing list