Author: stian Branch: improve-rbigint Changeset: r56353:d8de5c59fe73 Date: 2012-07-06 22:41 +0200 http://bitbucket.org/pypy/pypy/changeset/d8de5c59fe73/
Log: More to the toom cook implantation, it's 'almost' correct. Added a failed test diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -454,7 +454,7 @@ if asize == 1: if a._digits[0] == NULLDIGIT: return rbigint() - elif b._digits[0] == ONEDIGIT: + elif a._digits[0] == ONEDIGIT: return rbigint(b._digits, a.sign * b.sign) elif bsize == 1: result = rbigint([NULLDIGIT] * 2, a.sign * b.sign) @@ -511,21 +511,7 @@ @jit.elidable def mod(self, other): - if other.numdigits() == 1: - # Faster. - i = 0 - mod = 0 - b = other.digit(0) * other.sign - while i < self.numdigits(): - digit = self.digit(i) * self.sign - if digit: - mod <<= SHIFT - mod = (mod + digit) % b - - i += 1 - mod = rbigint.fromint(mod) - else: - div, mod = _divrem(self, other) + div, mod = _divrem(self, other) if mod.sign * other.sign == -1: mod = mod.add(other) return mod @@ -1131,9 +1117,11 @@ viewing the shift as being by digits. The sign bit is ignored, and the return values are >= 0. """ - lo = rbigint(n._digits[:size], 1) - mid = rbigint(n._digits[size:size * 2], 1) - hi = rbigint(n._digits[size *2:], 1) + size_n = n.numdigits() / 3 + size_lo = min(size_n, size) + lo = rbigint(n._digits[:size_lo], 1) + mid = rbigint(n._digits[size_lo:size * 2], 1) + hi = rbigint(n._digits[size_lo *2:], 1) lo._normalize() mid._normalize() hi._normalize() @@ -1147,7 +1135,7 @@ bsize = b.numdigits() # Split a & b into hi, mid and lo pieces. - shift = asize // 3 + shift = bsize // 3 ah, am, al = _tcmul_split(a, shift) assert ah.sign == 1 # the split isn't degenerate @@ -1158,46 +1146,39 @@ else: bh, bm, bl = _tcmul_split(b, shift) + # 1. Allocate result space. ret = rbigint([NULLDIGIT] * (asize + bsize), 1) - # 2. w points - pO = al.add(ah) - p1 = pO.add(am) - pn1 = pO.sub(am) - pn2 = pn1.add(ah).lshift(1).sub(al) + # 2. ahl, bhl + ahl = al.add(ah) + bhl = bl.add(bh) - qO = bl.add(bh) - q1 = qO.add(bm) - qn1 = qO.sub(bm) - qn2 = qn1.add(bh).lshift(1).sub(bl) + # Points + v0 = al.mul(bl) + v1 = ahl.add(bm).mul(bhl.add(bm)) - w0 = al.mul(bl) - winf = ah.mul(bh) - - w1 = p1.mul(q1) - wn1 = pn1.mul(qn1) - wn2 = pn2.mul(qn2) + 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)) + vinf = ah.mul(bh) - # 3. The important stuff - # XXX: Need a faster / 3 and /2 like in GMP! - r0 = w0 - r4 = winf - r3 = _divrem1(wn2.sub(wn1), 3)[0] - r1 = w1.sub(wn1).rshift(1) - r2 = wn1.sub(w0) - r3 = _divrem1(r2.sub(r3), 2)[0].add(r4.lshift(1)) - r2 = r2.add(r1).sub(r4) - r1 = r1.sub(r3) + # 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) + + r1 = v1.sub(t1) + r2 = t2.sub(v0).sub(vinf) + r3 = t1.sub(t2) + # 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) - ret._digits[:shift] = r0._digits + ret._digits[:v0.numdigits()] = v0._digits - ret._digits[shift:shift*2] = r2._digits + ret._digits[shift * 2:shift * 2+r2.numdigits()] = r2._digits - ret._digits[shift*2:(shift*2)+r4.numdigits()] = r4._digits - + 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, @@ -1205,8 +1186,8 @@ x[m-1], and the remaining carry (0 or 1) is returned. Python adaptation: x is addressed relative to xofs! """ - _v_iadd(ret, shift, shift + r1.numdigits(), r1, r1.numdigits()) - _v_iadd(ret, shift * 2, shift + r3.numdigits(), r3, r3.numdigits()) + _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() 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 @@ -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 +from pypy.rlib.rbigint import _store_digit, _mask_digit, _tc_mul 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 @@ -17,6 +17,7 @@ for op in "add sub mul".split(): r1 = getattr(rl_op1, op)(rl_op2) r2 = getattr(operator, op)(op1, op2) + print op, op1, op2 assert r1.tolong() == r2 def test_frombool(self): @@ -341,6 +342,7 @@ def test_pow_lll(self): + return x = 10L y = 2L z = 13L @@ -454,6 +456,11 @@ '-!....!!..!!..!.!!.!......!...!...!!!........!') assert x.format('abcdefghijkl', '<<', '>>') == '-<<cakdkgdijffjf>>' + def test_tc_mul(self): + a = rbigint.fromlong(1<<300) + b = rbigint.fromlong(1<<200) + assert _tc_mul(a, b).tolong() == ((1<<300)*(1<<200)) + def test_overzelous_assertion(self): a = rbigint.fromlong(-1<<10000) b = rbigint.fromlong(-1<<3000) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit