[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