[Jython-checkins] jython: Fix float.__mod__ to conform to spec.

jeff.allen jython-checkins at python.org
Wed Dec 31 02:41:07 CET 2014


https://hg.python.org/jython/rev/2472ea52bc76
changeset:   7479:2472ea52bc76
user:        Jeff Allen <ja.py at farowl.co.uk>
date:        Wed Dec 17 21:24:56 2014 +0000
summary:
  Fix float.__mod__ to conform to spec.

Fixes test failures in test_float by re-implementing using Java % and tweaks.

files:
  Lib/test/test_float.py           |   9 ++---
  src/org/python/core/PyFloat.java |  32 +++++++++++++++-----
  2 files changed, 28 insertions(+), 13 deletions(-)


diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
--- a/Lib/test/test_float.py
+++ b/Lib/test/test_float.py
@@ -217,10 +217,9 @@
         # In particular, check signs of zeros.
         mod = operator.mod
 
-        #FIXME: Jython fails some mod edge cases.
-        #self.assertEqualAndEqualSign(mod(-1.0, 1.0), 0.0)
+        self.assertEqualAndEqualSign(mod(-1.0, 1.0), 0.0)
         self.assertEqualAndEqualSign(mod(-1e-100, 1.0), 1.0)
-        #self.assertEqualAndEqualSign(mod(-0.0, 1.0), 0.0)
+        self.assertEqualAndEqualSign(mod(-0.0, 1.0), 0.0)
         self.assertEqualAndEqualSign(mod(0.0, 1.0), 0.0)
         self.assertEqualAndEqualSign(mod(1e-100, 1.0), 1e-100)
         self.assertEqualAndEqualSign(mod(1.0, 1.0), 0.0)
@@ -228,9 +227,9 @@
         self.assertEqualAndEqualSign(mod(-1.0, -1.0), -0.0)
         self.assertEqualAndEqualSign(mod(-1e-100, -1.0), -1e-100)
         self.assertEqualAndEqualSign(mod(-0.0, -1.0), -0.0)
-        #self.assertEqualAndEqualSign(mod(0.0, -1.0), -0.0)
+        self.assertEqualAndEqualSign(mod(0.0, -1.0), -0.0)
         self.assertEqualAndEqualSign(mod(1e-100, -1.0), -1.0)
-        #self.assertEqualAndEqualSign(mod(1.0, -1.0), -0.0)
+        self.assertEqualAndEqualSign(mod(1.0, -1.0), -0.0)
 
     @requires_IEEE_754
     def test_float_pow(self):
diff --git a/src/org/python/core/PyFloat.java b/src/org/python/core/PyFloat.java
--- a/src/org/python/core/PyFloat.java
+++ b/src/org/python/core/PyFloat.java
@@ -625,15 +625,30 @@
         return new PyFloat(leftv / getValue());
     }
 
+    /**
+     * Python % operator: y = n*x + z. The modulo operator always yields a result with the same sign
+     * as its second operand (or zero). (Compare <code>java.Math.IEEEremainder</code>)
+     *
+     * @param x dividend
+     * @param y divisor
+     * @return <code>x % y</code>
+     */
     private static double modulo(double x, double y) {
-        if (y == 0) {
+        if (y == 0.0) {
             throw Py.ZeroDivisionError("float modulo");
+        } else {
+            double z = x % y;
+            if (z == 0.0) {
+                // Has to be same sign as y (even when zero).
+                return Math.copySign(z, y);
+            } else if ((z > 0.0) == (y > 0.0)) {
+                // z has same sign as y, as it must.
+                return z;
+            } else {
+                // Note abs(z) < abs(y) and opposite sign.
+                return z + y;
+            }
         }
-        double z = Math.IEEEremainder(x, y);
-        if (z * y < 0) {
-            z += y;
-        }
-        return z;
     }
 
     @Override
@@ -934,8 +949,9 @@
     }
 
     /**
-     * Common code for PyFloat, {@link PyInteger} and {@link PyLong} to prepare a {@link FloatFormatter} from a parsed specification.
-     * The object returned has format method {@link FloatFormatter#format(double)}.
+     * Common code for PyFloat, {@link PyInteger} and {@link PyLong} to prepare a
+     * {@link FloatFormatter} from a parsed specification. The object returned has format method
+     * {@link FloatFormatter#format(double)}.
      *
      * @param spec a parsed PEP-3101 format specification.
      * @return a formatter ready to use, or null if the type is not a floating point format type.

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list