[pypy-commit] pypy default: fix float mod behavior to match cpython (issue 1873)

bdkearns noreply at buildbot.pypy.org
Wed Sep 24 18:51:18 CEST 2014


Author: Brian Kearns <bdkearns at gmail.com>
Branch: 
Changeset: r73681:42870fecc305
Date: 2014-09-24 09:50 -0700
http://bitbucket.org/pypy/pypy/changeset/42870fecc305/

Log:	fix float mod behavior to match cpython (issue 1873)

diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -15,6 +15,7 @@
 from rpython.rlib.rbigint import rbigint
 from rpython.rlib import rfloat
 from rpython.tool.sourcetools import func_with_new_name
+from rpython.rtyper.lltypesystem.module.ll_math import math_fmod
 
 from pypy.objspace.std.intobject import W_IntObject
 
@@ -360,21 +361,17 @@
     y = w_float2.floatval
     if y == 0.0:
         raise FailedToImplementArgs(space.w_ZeroDivisionError, space.wrap("float modulo"))
-    try:
-        mod = math.fmod(x, y)
-    except ValueError:
-        mod = rfloat.NAN
+    mod = math_fmod(x, y)
+    if mod:
+        # ensure the remainder has the same sign as the denominator
+        if (y < 0.0) != (mod < 0.0):
+            mod += y
     else:
-        if mod:
-            # ensure the remainder has the same sign as the denominator
-            if (y < 0.0) != (mod < 0.0):
-                mod += y
-        else:
-            # the remainder is zero, and in the presence of signed zeroes
-            # fmod returns different results across platforms; ensure
-            # it has the same sign as the denominator; we'd like to do
-            # "mod = y * 0.0", but that may get optimized away
-            mod = copysign(0.0, y)
+        # the remainder is zero, and in the presence of signed zeroes
+        # fmod returns different results across platforms; ensure
+        # it has the same sign as the denominator; we'd like to do
+        # "mod = y * 0.0", but that may get optimized away
+        mod = copysign(0.0, y)
 
     return W_FloatObject(mod)
 
@@ -383,10 +380,7 @@
     y = w_float2.floatval
     if y == 0.0:
         raise FailedToImplementArgs(space.w_ZeroDivisionError, space.wrap("float modulo"))
-    try:
-        mod = math.fmod(x, y)
-    except ValueError:
-        return [W_FloatObject(rfloat.NAN), W_FloatObject(rfloat.NAN)]
+    mod = math_fmod(x, y)
     # fmod is typically exact, so vx-mod is *mathematically* an
     # exact multiple of wx.  But this is fp arithmetic, and fp
     # vx - mod is an approximation; the result is that div may
diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -794,7 +794,7 @@
         raises(ValueError, float.fromhex, "0P")
 
     def test_division_edgecases(self):
-        import math
+        import math, os
 
         # inf
         inf = float("inf")
@@ -803,6 +803,16 @@
         x, y = divmod(inf, 3)
         assert math.isnan(x)
         assert math.isnan(y)
+        x, y = divmod(3, inf)
+        z = 3 % inf
+        if os.name == 'nt':
+            assert math.isnan(x)
+            assert math.isnan(y)
+            assert math.isnan(z)
+        else:
+            assert x == 0
+            assert y == 3
+            assert z == 3
 
         # divide by 0
         raises(ZeroDivisionError, lambda: inf % 0)


More information about the pypy-commit mailing list