Author: stian
Branch: 
Changeset: r92789:d420391a020a
Date: 2017-10-18 17:48 +0200
http://bitbucket.org/pypy/pypy/changeset/d420391a020a/

Log:    Add missing int_floordiv, int_divmod. Improves pidigits by about 5%

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
@@ -491,17 +491,18 @@
                         "long division or modulo by zero")
         return newlong(space, z)
 
-    def _floordiv(self, space, w_other):
+    def _int_floordiv(self, space, w_other):
         try:
-            z = self.num.floordiv(w_other.asbigint())
+            z = self.num.int_floordiv(w_other)
         except ZeroDivisionError:
             raise oefmt(space.w_ZeroDivisionError,
                         "long division or modulo by zero")
         return newlong(space, z)
-    descr_floordiv, descr_rfloordiv = _make_descr_binop(_floordiv)
+    descr_floordiv, descr_rfloordiv = _make_descr_binop(_floordiv, 
_int_floordiv)
 
     _div = func_with_new_name(_floordiv, '_div')
-    descr_div, descr_rdiv = _make_descr_binop(_div)
+    _int_div = func_with_new_name(_int_floordiv, '_int_div')
+    descr_div, descr_rdiv = _make_descr_binop(_div, _int_div)
 
     def _mod(self, space, w_other):
         try:
@@ -527,7 +528,16 @@
             raise oefmt(space.w_ZeroDivisionError,
                         "long division or modulo by zero")
         return space.newtuple([newlong(space, div), newlong(space, mod)])
-    descr_divmod, descr_rdivmod = _make_descr_binop(_divmod)
+        
+    def _int_divmod(self, space, w_other):
+        try:
+            div, mod = self.num.int_divmod(w_other)
+        except ZeroDivisionError:
+            raise oefmt(space.w_ZeroDivisionError,
+                        "long division or modulo by zero")
+        return space.newtuple([newlong(space, div), newlong(space, mod)])
+        
+    descr_divmod, descr_rdivmod = _make_descr_binop(_divmod, _int_divmod)
 
 
 def newlong(space, bigint):
diff --git a/pypy/objspace/std/test/test_longobject.py 
b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -70,6 +70,17 @@
         a = x // 10000000L
         assert a == 3L
 
+    def test_int_floordiv(self):
+        x = 3000L
+        a = x // 1000
+        assert a == 3L
+
+        x = 3000L
+        a = x // -1000
+        assert a == -3L
+
+
+
     def test_numerator_denominator(self):
         assert (1L).numerator == 1L
         assert (1L).denominator == 1L
@@ -208,6 +219,11 @@
         check_division(x, y)
         raises(ZeroDivisionError, "x // 0L")
 
+    def test_int_divmod(self):
+        q, r = divmod(100L, 11)
+        assert q == 9L
+        assert r == 1L
+        
     def test_format(self):
         assert repr(12345678901234567890) == '12345678901234567890L'
         assert str(12345678901234567890) == '12345678901234567890'
@@ -386,3 +402,4 @@
         n = "a" * size
         expected = (2 << (size * 4)) // 3
         assert long(n, 16) == expected
+
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -781,7 +781,34 @@
 
     def div(self, other):
         return self.floordiv(other)
-
+        
+    @jit.elidable
+    def int_floordiv(self, b):
+        if not int_in_valid_range(b):
+            # Fallback to long.
+            return self.mul(rbigint.fromint(b))
+        
+        digit = abs(b)
+        assert digit > 0
+
+        if self.sign == 1 and b > 0:
+            if digit == 1:
+                return self
+            """elif digit & (digit - 1) == 0:
+                return self.rshift(ptwotable[digit])
+            """
+        div, mod = _divrem1(self, digit)
+
+        if mod != 0 and self.sign * (-1 if b < 0 else 1) == -1:
+            if div.sign == 0:
+                return ONENEGATIVERBIGINT
+            div = div.int_add(1)
+        div.sign = self.sign * (-1 if b < 0 else 1)
+        return div
+
+    def int_div(self, other):
+        return self.int_floordiv(other)
+        
     @jit.elidable
     def mod(self, other):
         if self.sign == 0:
@@ -888,6 +915,30 @@
         return div, mod
 
     @jit.elidable
+    def int_divmod(v, w):
+        """ Divmod with int """
+
+        if w == 0:
+            raise ZeroDivisionError("long division or modulo by zero")
+
+        wsign = (-1 if w < 0 else 1)
+        if not int_in_valid_range(w) or v.sign != wsign:
+            # Divrem1 doesn't deal with the sign difference. Instead of having 
yet another copy,
+            # Just fallback.
+            return v.divmod(rbigint.fromint(w))
+
+        digit = abs(w)
+        assert digit > 0
+
+        div, mod = _divrem1(v, digit)
+        mod = rbigint.fromint(mod)
+        
+        mod.sign = wsign
+        div.sign = v.sign * wsign
+
+        return div, mod
+        
+    @jit.elidable
     def pow(a, b, c=None):
         negativeOutput = False  # if x<0 return negative output
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to