Author: stian
Branch: improve-rbigint
Changeset: r56318:fb9c7d03ec58
Date: 2012-06-22 23:37 +0200
http://bitbucket.org/pypy/pypy/changeset/fb9c7d03ec58/
Log: Futher improvements, two more tests
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -93,9 +93,7 @@
class rbigint(object):
"""This is a reimplementation of longs using a list of digits."""
- def __init__(self, digits=[], sign=0):
- if len(digits) == 0:
- digits = [NULLDIGIT]
+ def __init__(self, digits=[NULLDIGIT], sign=0):
_check_digits(digits)
make_sure_not_resized(digits)
self._digits = digits
@@ -374,7 +372,7 @@
result = _x_mul(self, other)
result.sign = self.sign * other.sign
return result
-
+
def truediv(self, other):
div = _bigint_true_divide(self, other)
return div
@@ -450,27 +448,29 @@
if a.sign < 0:
a, temp = a.divmod(c)
a = temp
-
+
+ size_b = b.numdigits()
+
# At this point a, b, and c are guaranteed non-negative UNLESS
# c is NULL, in which case a may be negative. */
- z = rbigint([_store_digit(1)], 1)
-
+ z = rbigint([ONEDIGIT], 1)
+
# python adaptation: moved macros REDUCE(X) and MULT(X, Y, result)
# into helper function result = _help_mult(x, y, c)
- if b.numdigits() <= FIVEARY_CUTOFF:
+ if not c or size_b <= FIVEARY_CUTOFF:
# Left-to-right binary exponentiation (HAC Algorithm 14.79)
# http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
- i = b.numdigits() - 1
- while i >= 0:
- bi = b.digit(i)
+ size_b -= 1
+ while size_b >= 0:
+ bi = b.digit(size_b)
j = 1 << (SHIFT-1)
while j != 0:
z = _help_mult(z, z, c)
if bi & j:
z = _help_mult(z, a, c)
j >>= 1
- i -= 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.
@@ -479,7 +479,7 @@
table[0] = z
for i in range(1, 32):
table[i] = _help_mult(table[i-1], a, c)
- i = b.numdigits()
+
# Note that here SHIFT is not a multiple of 5. The difficulty
# is to extract 5 bits at a time from 'b', starting from the
# most significant digits, so that at the end of the algorithm
@@ -488,11 +488,11 @@
# m+ = m rounded up to the next multiple of 5
# j = (m+) % SHIFT = (m+) - (i * SHIFT)
# (computed without doing "i * SHIFT", which might overflow)
- j = i % 5
+ j = size_b % 5
if j != 0:
j = 5 - j
if not we_are_translated():
- assert j == (i*SHIFT+4)//5*5 - i*SHIFT
+ assert j == (size_b*SHIFT+4)//5*5 - size_b*SHIFT
#
accum = r_uint(0)
while True:
@@ -502,10 +502,12 @@
else:
# 'accum' does not have enough digit.
# must get the next digit from 'b' in order to complete
- i -= 1
- if i < 0:
- break # done
- bi = b.udigit(i)
+ if size_b == 0:
+ break # Done
+
+ size_b -= 1
+
+ bi = b.udigit(size_b)
index = ((accum << (-j)) | (bi >> (j+SHIFT))) & 0x1f
accum = bi
j += SHIFT
@@ -563,13 +565,11 @@
def lqshift(self, int_other):
" A quicker one with much less checks, int_other is valid and for the
most part constant."
- if int_other == 0:
- return self
+ assert int_other > 0
oldsize = self.numdigits()
- newsize = oldsize + 1
- z = rbigint([NULLDIGIT] * newsize, self.sign)
+ z = rbigint([NULLDIGIT] * (oldsize + 1), self.sign)
accum = _widen_digit(0)
for i in range(oldsize):
@@ -577,7 +577,7 @@
z.setdigit(i, accum)
accum >>= SHIFT
- z.setdigit(newsize - 1, accum)
+ z.setdigit(oldsize, accum)
z._normalize()
return z
@@ -701,12 +701,10 @@
# Perform a modular reduction, X = X % c, but leave X alone if c
# is NULL.
if c is not None:
- res, temp = res.divmod(c)
- res = temp
+ temp, res = res.divmod(c)
+
return res
-
-
def digits_from_nonneg_long(l):
digits = []
while True:
@@ -850,21 +848,21 @@
ptwotable[2 << x] = x+1
ptwotable[-2 << x] = x+1
-def _x_mul(a, b):
+def _x_mul(a, b, digit=0):
"""
Grade school multiplication, ignoring the signs.
Returns the absolute value of the product, or None if error.
"""
size_a = a.numdigits()
-
+
if size_a == 1:
# Special case.
digit = a.digit(0)
if digit == 0:
return rbigint([NULLDIGIT], 1)
elif digit == 1:
- return rbigint(b._digits[:], 1)
+ return rbigint(b._digits[:], 1) # We assume b was normalized
already.
size_b = b.numdigits()
@@ -909,33 +907,31 @@
i += 1
z._normalize()
return z
- else:
- if size_a == 1:
- digit = a.digit(0)
- if digit & (digit - 1) == 0:
- return b.lqshift(ptwotable[digit])
-
- z = rbigint([NULLDIGIT] * (size_a + size_b), 1)
- # gradeschool long mult
- i = 0
- while i < size_a:
- carry = 0
- f = a.widedigit(i)
- pz = i
- pb = 0
- while pb < size_b:
- carry += z.widedigit(pz) + b.widedigit(pb) * f
- pb += 1
- z.setdigit(pz, carry)
- pz += 1
- carry >>= SHIFT
- assert carry <= MASK
- if carry:
- z.setdigit(pz, z.widedigit(pz) + carry)
- assert (carry >> SHIFT) == 0
- i += 1
- z._normalize()
- return z
+
+ elif digit and digit & (digit - 1) == 0:
+ return b.lqshift(ptwotable[digit])
+
+ z = rbigint([NULLDIGIT] * (size_a + size_b), 1)
+ # gradeschool long mult
+ i = 0
+ while i < size_a:
+ carry = 0
+ f = a.widedigit(i)
+ pz = i
+ pb = 0
+ while pb < size_b:
+ carry += z.widedigit(pz) + b.widedigit(pb) * f
+ pb += 1
+ z.setdigit(pz, carry)
+ pz += 1
+ carry >>= SHIFT
+ assert carry <= MASK
+ if carry:
+ z.setdigit(pz, z.widedigit(pz) + carry)
+ assert (carry >> SHIFT) == 0
+ i += 1
+ z._normalize()
+ return z
def _kmul_split(n, size):
@@ -1140,7 +1136,8 @@
# Successive slices of b are copied into bslice.
#bslice = rbigint([0] * asize, 1)
# XXX we cannot pre-allocate, see comments below!
- bslice = rbigint([NULLDIGIT], 1)
+ # XXX prevent one list from being created.
+ bslice = rbigint(sign = 1)
nbdone = 0;
while bsize > 0:
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
@@ -10,6 +10,7 @@
"""
A cutout with some benchmarks.
Pypy default:
+ <No run yet>
18.270045
2.512140
14.148920
@@ -17,13 +18,23 @@
6.647562
Pypy with improvements:
- 15.211410
- 1.707288
- 13.955348
- 14.474590
- 6.446812
+ 6.048997
+ 10.091559
+ 14.680590
+ 1.635417
+ 12.023154
+ 14.320596
+ 6.464143
"""
+
+ t = time()
+ num = rbigint.pow(rbigint.fromint(10000), rbigint.fromint(2 ** 8))
+ for n in xrange(60000):
+ rbigint.pow(rbigint.fromint(10**4), num, rbigint.fromint(100))
+
+
+ print time() - t
t = time()
i = rbigint.fromint(2**31)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit