[pypy-commit] pypy improve-rbigint: Remove toom-cook (since it didn't pass own-linux-x86-32), fix divmod test.

stian noreply at buildbot.pypy.org
Thu Jul 26 18:01:29 CEST 2012


Author: stian
Branch: improve-rbigint
Changeset: r56474:e0eaeb5fd308
Date: 2012-07-26 17:59 +0200
http://bitbucket.org/pypy/pypy/changeset/e0eaeb5fd308/

Log:	Remove toom-cook (since it didn't pass own-linux-x86-32), fix divmod
	test.

diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -66,9 +66,6 @@
     
 KARATSUBA_SQUARE_CUTOFF = 2 * KARATSUBA_CUTOFF
 
-USE_TOOMCOCK = False
-TOOMCOOK_CUTOFF = 10000 # 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.
 # In that case, do 5 bits at a time.  The potential drawback is that
@@ -441,8 +438,6 @@
                     return rbigint([_store_digit(res & MASK)], a.sign * b.sign, 1)
                 
             result =  _x_mul(a, b, a.digit(0))
-        elif USE_TOOMCOCK and asize >= TOOMCOOK_CUTOFF:
-            result = _tc_mul(a, b)
         elif USE_KARATSUBA:
             if a is b:
                 i = KARATSUBA_SQUARE_CUTOFF
@@ -1109,94 +1104,6 @@
     return z
 
 
-def _tcmul_split(n):
-    """
-    A helper for Karatsuba multiplication (k_mul).
-    Takes a bigint "n" and an integer "size" representing the place to
-    split, and sets low and high such that abs(n) == (high << (size * 2) + (mid << size) + low,
-    viewing the shift as being by digits.  The sign bit is ignored, and
-    the return values are >= 0.
-    """
-    size_n = n.numdigits() // 3
-    lo = rbigint(n._digits[:size_n], 1)
-    mid = rbigint(n._digits[size_n:size_n * 2], 1)
-    hi = rbigint(n._digits[size_n *2:], 1)
-    lo._normalize()
-    mid._normalize()
-    hi._normalize()
-    return hi, mid, lo
-
-THREERBIGINT = rbigint.fromint(3)
-def _tc_mul(a, b):
-    """
-    Toom Cook
-    """
-    asize = a.numdigits()
-    bsize = b.numdigits()
-
-    # Split a & b into hi, mid and lo pieces.
-    shift = bsize // 3
-    ah, am, al = _tcmul_split(a)
-    assert ah.sign == 1    # the split isn't degenerate
-
-    if a is b:
-        bh = ah
-        bm = am
-        bl = al
-    else:
-        bh, bm, bl = _tcmul_split(b)
-        
-    # 2. ahl, bhl
-    ahl = al.add(ah)
-    bhl = bl.add(bh)
-
-    # Points
-    v0 = al.mul(bl)
-    v1 = ahl.add(bm).mul(bhl.add(bm))
-
-    vn1 = ahl.sub(bm).mul(bhl.sub(bm))
-    v2 = al.add(am.lqshift(1)).add(ah.lshift(2)).mul(bl.add(bm.lqshift(1)).add(bh.lqshift(2)))
-
-    vinf = ah.mul(bh)
-
-    # Construct
-    t1 = v0.mul(THREERBIGINT).add(vn1.lqshift(1)).add(v2)
-    _inplace_divrem1(t1, t1, 6)
-    t1 = t1.sub(vinf.lqshift(1))
-    t2 = v1
-    _v_iadd(t2, 0, t2.numdigits(), vn1, vn1.numdigits())
-    _v_rshift(t2, t2, t2.numdigits(), 1)
-
-    r1 = v1.sub(t1)
-    r2 = t2
-    _v_isub(r2, 0, r2.numdigits(), v0, v0.numdigits())
-    r2 = r2.sub(vinf)
-    r3 = t1
-    _v_isub(r3, 0, r3.numdigits(), t2, t2.numdigits())
-
-    # Now we fit t+ t2 + t4 into the new string.
-    # Now we got to add the r1 and r3 in the mid shift.
-    # Allocate result space.
-    ret = rbigint([NULLDIGIT] * (4 * shift + vinf.numdigits() + 1), 1)  # This is because of the size of vinf
-    
-    ret._digits[:v0.numdigits()] = v0._digits
-    assert t2.sign >= 0
-    assert 2*shift + t2.numdigits() < ret.numdigits()
-    ret._digits[shift * 2:shift * 2+r2.numdigits()] = r2._digits
-    assert vinf.sign >= 0
-    assert 4*shift + vinf.numdigits() <= ret.numdigits()
-    ret._digits[shift*4:shift*4+vinf.numdigits()] = vinf._digits
-
-
-    i = ret.numdigits() - shift
-    _v_iadd(ret, shift * 3, i, r3, r3.numdigits())
-    _v_iadd(ret, shift, i, r1, r1.numdigits())
-    
-
-    ret._normalize()
-    return ret
-
-
 def _kmul_split(n, size):
     """
     A helper for Karatsuba multiplication (k_mul).
@@ -1556,20 +1463,9 @@
     size_v = v.numdigits()
     size_w = w.numdigits()
     assert size_w > 1 # (Assert checks by div()
-
-    """v = rbigint([NULLDIGIT] * (size_v + 1))
-    w = rbigint([NULLDIGIT] * (size_w))
-    
-    d = SHIFT - bits_in_digit(w1.digit(size_w-1))
-    carry = _v_lshift(w, w1, size_w, d)
-    assert carry == 0
-    carrt = _v_lshift(v, v1, size_v, d)
-    if carry != 0 or v.digit(size_v - 1) >= w.digit(size_w-1):
-        v.setdigit(size_v, carry)
-        size_v += 1"""
         
     size_a = size_v - size_w + 1
-    assert size_a >= 0
+    assert size_a > 0
     a = rbigint([NULLDIGIT] * size_a, 1, size_a)
 
     wm1 = w.widedigit(abs(size_w-1))
@@ -1635,95 +1531,6 @@
     _inplace_divrem1(v, v, d, size_v)
     v._normalize()
     return a, v
-
-    """
-    Didn't work as expected. Someone want to look over this?
-    size_v = v1.numdigits()
-    size_w = w1.numdigits()
-    
-    assert size_v >= size_w and size_w >= 2
-    
-    v = rbigint([NULLDIGIT] * (size_v + 1))
-    w = rbigint([NULLDIGIT] * size_w)
-    
-    # Normalization
-    d = SHIFT - bits_in_digit(w1.digit(size_w-1))
-    carry = _v_lshift(w, w1, size_w, d)
-    assert carry == 0
-    carry = _v_lshift(v, v1, size_v, d)
-    if carry != 0 or v.digit(size_v-1) >= w.digit(size_w-1):
-        v.setdigit(size_v, carry)
-        size_v += 1
-        
-    # Now v->ob_digit[size_v-1] < w->ob_digit[size_w-1], so quotient has
-    # at most (and usually exactly) k = size_v - size_w digits.
-    
-    k = size_v - size_w
-    assert k >= 0
-    
-    a = rbigint([NULLDIGIT] * k)
-    
-    k -= 1
-    wm1 = w.digit(size_w-1)
-    wm2 = w.digit(size_w-2)
-    
-    j = size_v
-    
-    while k >= 0:
-        # inner loop: divide vk[0:size_w+1] by w[0:size_w], giving
-        # single-digit quotient q, remainder in vk[0:size_w].
-            
-        vtop = v.widedigit(size_w)
-        assert vtop <= wm1
-        
-        vv = vtop << SHIFT | v.digit(size_w-1)
-        
-        q = vv / wm1
-        r = vv - _widen_digit(wm1) * q
-        
-        # estimate quotient digit q; may overestimate by 1 (rare)
-        while wm2 * q > ((r << SHIFT) | v.digit(size_w-2)):
-            q -= 1
-            
-            r+= wm1
-            if r >= SHIFT:
-                break
-                
-        assert q <= BASE
-        
-        # subtract q*w0[0:size_w] from vk[0:size_w+1]
-        zhi = 0
-        for i in range(size_w):
-            #invariants: -BASE <= -q <= zhi <= 0;
-            #    -BASE * q <= z < ASE
-            z = v.widedigit(i+k) + zhi - (q * w.widedigit(i))
-            v.setdigit(i+k, z)
-            zhi = z >> SHIFT
-            
-        # add w back if q was too large (this branch taken rarely)
-        assert vtop + zhi == -1 or vtop + zhi == 0
-        if vtop + zhi < 0:
-            carry = 0
-            for i in range(size_w):
-                carry += v.digit(i+k) + w.digit(i)
-                v.setdigit(i+k, carry)
-                carry >>= SHIFT
-                
-            q -= 1
-           
-        assert q < BASE
-        
-        a.setdigit(k, q)
-
-        j -= 1
-        k -= 1
-        
-    carry = _v_rshift(w, v, size_w, d)
-    assert carry == 0
-    
-    a._normalize()
-    w._normalize()
-    return a, w"""
         
 def _divrem(a, b):
     """ Long division with remainder, top-level routine """
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
@@ -3,7 +3,7 @@
 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, _mask_digit, _tc_mul
+from pypy.rlib.rbigint import _store_digit, _mask_digit
 from pypy.rlib import rbigint as lobj
 from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, intmask
 from pypy.rpython.test.test_llinterp import interpret
@@ -462,12 +462,6 @@
         assert x.format('.!') == (
             '-!....!!..!!..!.!!.!......!...!...!!!........!')
         assert x.format('abcdefghijkl', '<<', '>>') == '-<<cakdkgdijffjf>>'
-
-    def test_tc_mul(self):
-        a = rbigint.fromlong(1<<200)
-        b = rbigint.fromlong(1<<300)
-        print _tc_mul(a, b)
-        assert _tc_mul(a, b).tolong() == ((1<<300)*(1<<200))
         
     def test_overzelous_assertion(self):
         a = rbigint.fromlong(-1<<10000)
@@ -536,17 +530,17 @@
     def test__x_divrem(self):
         x = 12345678901234567890L
         for i in range(100):
-            y = long(randint(0, 1 << 60))
+            y = long(randint(1, 1 << 60))
             y <<= 60
-            y += randint(0, 1 << 60)
+            y += randint(1, 1 << 60)
             f1 = rbigint.fromlong(x)
             f2 = rbigint.fromlong(y)
             div, rem = lobj._x_divrem(f1, f2)
             _div, _rem = divmod(x, y)
-            print div.tolong() == _div
-            print rem.tolong() == _rem
+            assert div.tolong() == _div
+            assert rem.tolong() == _rem
 
-    def test__divrem(self):
+    def test_divmod(self):
         x = 12345678901234567890L
         for i in range(100):
             y = long(randint(0, 1 << 60))
@@ -557,10 +551,10 @@
                 sy *= y
                 f1 = rbigint.fromlong(sx)
                 f2 = rbigint.fromlong(sy)
-                div, rem = lobj._x_divrem(f1, f2)
+                div, rem = f1.divmod(f2)
                 _div, _rem = divmod(sx, sy)
-                print div.tolong() == _div
-                print rem.tolong() == _rem
+                assert div.tolong() == _div
+                assert rem.tolong() == _rem
 
     # testing Karatsuba stuff
     def test__v_iadd(self):


More information about the pypy-commit mailing list