[pypy-commit] pypy bigint-with-int-ops: Support the modulo op
stian
noreply at buildbot.pypy.org
Fri Aug 9 00:11:45 CEST 2013
Author: stian
Branch: bigint-with-int-ops
Changeset: r66024:5ce749f54baf
Date: 2013-08-08 22:49 +0200
http://bitbucket.org/pypy/pypy/changeset/5ce749f54baf/
Log: Support the modulo op
diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py
--- a/pypy/objspace/std/longobject.py
+++ b/pypy/objspace/std/longobject.py
@@ -237,6 +237,14 @@
space.wrap("long division or modulo by zero"))
return newlong(space, z)
+def mod__Long_Int(space, w_long1, w_int2):
+ try:
+ z = w_long1.num.int_mod(w_int2.intval)
+ except ZeroDivisionError:
+ raise OperationError(space.w_ZeroDivisionError,
+ space.wrap("long division or modulo by zero"))
+ return newlong(space, z)
+
def divmod__Long_Long(space, w_long1, w_long2):
try:
div, mod = w_long1.num.divmod(w_long2.num)
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -755,6 +755,48 @@
return mod
@jit.elidable
+ def int_mod(self, other):
+ if self.sign == 0:
+ return NULLRBIGINT
+
+ elif not int_in_valid_range(other):
+ # Fallback to long.
+ return self.mod(rbigint.fromint(other))
+
+ elif other != 0:
+ digit = abs(other)
+ if digit == 1:
+ return NULLRBIGINT
+ elif digit == 2:
+ modm = self.digit(0) & 1
+ if modm:
+ return ONENEGATIVERBIGINT if other < 0 else ONERBIGINT
+ return NULLRBIGINT
+ elif digit & (digit - 1) == 0:
+ mod = self.and_(rbigint([_store_digit(digit - 1)], 1, 1))
+ else:
+ # Perform
+ size = self.numdigits() - 1
+ if size > 0:
+ rem = self.widedigit(size)
+ size -= 1
+ while size >= 0:
+ rem = ((rem << SHIFT) + self.widedigit(size)) % digit
+ size -= 1
+ else:
+ rem = self.digit(0) % digit
+
+ if rem == 0:
+ return NULLRBIGINT
+ mod = rbigint([_store_digit(rem)], -1 if self.sign < 0 else 1, 1)
+ else:
+ raise ZeroDivisionError("long division or modulo by zero")
+
+ if mod.sign * (-1 if other < 0 else 1) == -1:
+ mod = mod.int_add(other)
+ return mod
+
+ @jit.elidable
def divmod(v, w):
"""
The / and % operators are now defined in terms of divmod().
diff --git a/rpython/rlib/test/test_rbigint.py b/rpython/rlib/test/test_rbigint.py
--- a/rpython/rlib/test/test_rbigint.py
+++ b/rpython/rlib/test/test_rbigint.py
@@ -106,6 +106,15 @@
print op1, op2
assert r1.tolong() == r2
+ def test_int_mod(self):
+ for op1 in [-50, -12, -2, -1, 1, 2, 50, 52]:
+ for op2 in [-4, -2, -1, 1, 2, 8]:
+ rl_op1 = rbigint.fromint(op1)
+ r1 = rl_op1.int_mod(op2)
+ r2 = op1 % op2
+ print op1, op2
+ assert r1.tolong() == r2
+
def test_pow(self):
for op1 in [-50, -12, -2, -1, 1, 2, 50, 52]:
for op2 in [0, 1, 2, 8, 9, 10, 11]:
More information about the pypy-commit
mailing list