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

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
@@ -1159,12 +1155,15 @@

vn1 = ahl.sub(bm).mul(bhl.sub(bm))
vinf = ah.mul(bh)

# Construct
+    _inplace_divrem1(t1, t1, 6)
+    t1 = t1.sub(vinf.lshift(1))
+    _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.
-    """
-    _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))
```