[Jython-checkins] jython: Remove checks from math where java.lang.Math suffices.

jeff.allen jython-checkins at python.org
Tue Jan 6 20:23:01 CET 2015


https://hg.python.org/jython/rev/dbfba99fe271
changeset:   7509:dbfba99fe271
user:        Jeff Allen <ja.py at farowl.co.uk>
date:        Mon Jan 05 21:12:54 2015 +0000
summary:
  Remove checks from math where java.lang.Math suffices.

java.lang.Math often does the right thing for Python, and never
raises. In some cases we need to convert a nan or inf returned, into
a Python domain or range error.

files:
  src/org/python/modules/math.java |  214 ++++++++----------
  1 files changed, 98 insertions(+), 116 deletions(-)


diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java
--- a/src/org/python/modules/math.java
+++ b/src/org/python/modules/math.java
@@ -67,13 +67,7 @@
     }
 
     public static double acos(double v) {
-        if (isinf(v)) {
-            throwMathDomainValueError();
-        }
-        if (isnan(v)) {
-            return v;
-        }
-        return Math.acos(v);
+        return exceptNaN(Math.acos(v), v);
     }
 
     /**
@@ -108,13 +102,7 @@
     }
 
     public static double asin(double v) {
-        if (isinf(v)) {
-            throwMathDomainValueError();
-        }
-        if (isnan(v)) {
-            return v;
-        }
-        return Math.asin(v);
+        return exceptNaN(Math.asin(v), v);
     }
 
     public static double asinh(double v) {
@@ -147,17 +135,14 @@
     }
 
     public static double atan(double v) {
-        if (isnan(v)) {
-            return v;
-        }
-        return Math.atan(v);
+        return exceptNaN(Math.atan(v), v);
     }
 
     /**
      * Compute <i>tanh<sup>-1</sup>y</i>.
      *
      * @param y
-     * @return x such that <i>tanh x = y</i>
+     * @return <i>x</i> such that <i>tanh x = y</i>
      */
     public static double atanh(double y) {
         double absy = Math.abs(y);
@@ -180,34 +165,19 @@
     }
 
     public static double ceil(double v) {
-        if (isnan(v) || isinf(v)) {
-            return v;
-        }
         return Math.ceil(v);
     }
 
     public static double cos(double v) {
-        if (isinf(v)) {
-            throwMathDomainValueError();
-        }
-        if (isnan(v)) {
-            return NAN;
-        }
-        return Math.cos(v);
+        return exceptNaN(Math.cos(v), v);
     }
 
     public static double cosh(double v) {
-        return Math.cosh(v);
+        return exceptInf(Math.cosh(v), v);
     }
 
     public static double exp(double v) {
-        if (isninf(v)) {
-            return ZERO;
-        }
-        if (isnan(v) || isinf(v)) {
-            return v;
-        }
-        return check(Math.exp(v));
+        return exceptInf(Math.exp(v), v);
     }
 
     public static double floor(PyObject v) {
@@ -215,9 +185,6 @@
     }
 
     public static double floor(double v) {
-        if (isnan(v) || isinf(v)) {
-            return v;
-        }
         return Math.floor(v);
     }
 
@@ -232,10 +199,7 @@
         } else {
             doubleValue = log(v.asDouble());
         }
-        if (base != null) {
-            return check(applyLoggedBase(doubleValue, base));
-        }
-        return doubleValue;
+        return (base == null) ? doubleValue : applyLoggedBase(doubleValue, base);
     }
 
     public static double pow(double v, double w) {
@@ -254,7 +218,7 @@
             } else if (w > ZERO || ispinf(w)) {
                 return ZERO;
             } else {
-                throwMathDomainValueError();
+                throw mathDomainError();
             }
         }
         if (isninf(v)) {
@@ -301,7 +265,7 @@
             }
         }
         if (v < ZERO && !isIntegral(w)) {
-            throwMathDomainValueError();
+            throw mathDomainError();
         }
         return Math.pow(v, w);
     }
@@ -311,13 +275,7 @@
     }
 
     public static double sin(double v) {
-        if (isinf(v)) {
-            throwMathDomainValueError();
-        }
-        if (isnan(v)) {
-            return v;
-        }
-        return Math.sin(v);
+        return exceptNaN(Math.sin(v), v);
     }
 
     public static double sqrt(PyObject v) {
@@ -325,26 +283,11 @@
     }
 
     public static double sqrt(double v) {
-        if (isnan(v)) {
-            return v;
-        }
-        if (ispinf(v)) {
-            return v;
-        }
-        if (isninf(v) || v < MINUS_ZERO) {
-            throwMathDomainValueError();
-        }
-        return Math.sqrt(v);
+        return exceptNaN(Math.sqrt(v), v);
     }
 
     public static double tan(double v) {
-        if (isnan(v)) {
-            return NAN;
-        }
-        if (isinf(v)) {
-            throw Py.ValueError("math domain error");
-        }
-        return Math.tan(v);
+        return exceptNaN(Math.tan(v), v);
     }
 
     public static double log10(PyObject v) {
@@ -352,7 +295,7 @@
             int exp[] = new int[1];
             double x = ((PyLong)v).scaledDoubleValue(exp);
             if (x <= ZERO) {
-                throwMathDomainValueError();
+                throw mathDomainError();
             }
             return log10(x) + (exp[0] * EIGHT) * log10(TWO);
         }
@@ -360,11 +303,11 @@
     }
 
     public static double sinh(double v) {
-        return Math.sinh(v);
+        return exceptInf(Math.sinh(v), v);
     }
 
     public static double tanh(double v) {
-        return Math.tanh(v);
+        return exceptInf(Math.tanh(v), v);
     }
 
     public static double fabs(double v) {
@@ -379,10 +322,10 @@
             return v;
         }
         if (w == ZERO) {
-            throwMathDomainValueError();
+            throw mathDomainError();
         }
         if (isinf(v) && w == ONE) {
-            throwMathDomainValueError();
+            throw mathDomainError();
         }
         return v % w;
     }
@@ -468,11 +411,12 @@
     }
 
     public static double radians(double v) {
-        return check(Math.toRadians(v));
+        return Math.toRadians(v);
     }
 
     public static double degrees(double v) {
-        return check(Math.toDegrees(v));
+        // Note that this does not raise overflow in Python: 1e307 -> inf as in Java.
+        return Math.toDegrees(v);
     }
 
     public static boolean isnan(double v) {
@@ -501,24 +445,27 @@
     public static PyLong factorial(double v) {
         if (v == ZERO || v == ONE) {
             return new PyLong(1);
+        } else if (v < ZERO || isnan(v) || isinf(v)) {
+            throw mathDomainError();
+        } else if (!isIntegral(v)) {
+            throw mathDomainError();
+        } else {
+            // long input should be big enough :-)
+            long value = (long)v;
+            BigInteger bi = new BigInteger(Long.toString(value));
+            for (long l = value - 1; l > 1; l--) {
+                bi = bi.multiply(new BigInteger(Long.toString(l)));
+            }
+            return new PyLong(bi);
         }
-        if (v < ZERO || isnan(v) || isinf(v)) {
-            throwMathDomainValueError();
-        }
-        if (!isIntegral(v)) {
-            throwMathDomainValueError();
-        }
-        // long input should be big enough :-)
-        long value = (long)v;
-        BigInteger bi = new BigInteger(Long.toString(value));
-        for (long l = value - 1; l > 1; l--) {
-            bi = bi.multiply(new BigInteger(Long.toString(l)));
-        }
-        return new PyLong(bi);
     }
 
     public static double log1p(double v) {
-        return log(ONE + v);
+        if (v <= -1.) {
+            throw mathDomainError();
+        } else {
+            return Math.log1p(v);
+        }
     }
 
     public static double fsum(final PyObject iterable) {
@@ -530,7 +477,7 @@
         int exp[] = new int[1];
         double x = v.scaledDoubleValue(exp);
         if (x <= ZERO) {
-            throwMathDomainValueError();
+            throw mathDomainError();
         }
         return log(x) + (exp[0] * EIGHT) * log(TWO);
     }
@@ -542,27 +489,23 @@
         } else {
             loggedBase = log(base.asDouble());
         }
-        return check(loggedValue / loggedBase);
+        return loggedValue / loggedBase;
     }
 
     private static double log(double v) {
-        if (isninf(v) || v <= ZERO) {
-            throwMathDomainValueError();
+        if (v <= 0.) {
+            throw mathDomainError();
+        } else {
+            return Math.log(v);
         }
-        if (isinf(v) || isnan(v)) {
-            return v;
-        }
-        return Math.log(v);
     }
 
     private static double log10(double v) {
-        if (isninf(v)) {
-            throwMathDomainValueError();
+        if (v <= 0.) {
+            throw mathDomainError();
+        } else {
+            return Math.log10(v);
         }
-        if (isinf(v) || isnan(v)) {
-            return v;
-        }
-        return Math.log10(v);
     }
 
     private static boolean isninf(double v) {
@@ -606,25 +549,64 @@
         return Py.OverflowError("math range error");
     }
 
-    private static void throwMathDomainValueError() {
-        throw Py.ValueError("math domain error");
-    }
-
-    private static double check(double v) {
-        if (isnan(v)) {
-            throwMathDomainValueError();
-        }
+    private static double checkOverflow(double v) {
         if (isinf(v)) {
             throw Py.OverflowError("math range error");
         }
         return v;
     }
 
-    private static double checkOverflow(double v) {
-        if (isinf(v)) {
+    /**
+     * Turn a <code>NaN</code> result into a thrown <code>ValueError</code>, a math domain error, if
+     * the original argument was not itself <code>NaN</code>. Use as:
+     *
+     * <pre>
+     * public static double asin(double v) { return exceptNaN(Math.asin(v), v); }
+     * </pre>
+     *
+     * Note that the original function argument is also supplied to this method. Most Java math
+     * library methods do exactly what we need for Python, but some return {@value Double#NaN} when
+     * Python should raise <code>ValueError</code>. This is a brief way to change that.
+     *
+     * @param result to return (if we return)
+     * @param arg to include in check
+     * @return result if <code>arg</code> was <code>NaN</code> or <code>result</code> was not
+     *         <code>NaN</code>
+     * @throws PyException (ValueError) if <code>result</code> was <code>NaN</code> and
+     *             <code>arg</code> was not <code>NaN</code>
+     */
+    private static double exceptNaN(double result, double arg) throws PyException {
+        if (Double.isNaN(result) && !Double.isNaN(arg)) {
+            throw mathDomainError();
+        } else {
+            return result;
+        }
+    }
+
+    /**
+     * Turn an infinite result into a thrown <code>OverflowError</code>, a math range error, if the
+     * original argument was not itself infinite. Use as:
+     *
+     * <pre>
+     * public static double cosh(double v) { return exceptInf( Math.cosh(v), v); }
+     * </pre>
+     *
+     * Note that the original function argument is also supplied to this method. Most Java math
+     * library methods do exactly what we need for Python, but some return an infinity when Python
+     * should raise <code>OverflowError</code>. This is a brief way to change that.
+     *
+     * @param result to return (if we return)
+     * @param arg to include in check
+     * @return result if <code>arg</code> was infinite or <code>result</code> was not infinite
+     * @throws PyException (ValueError) if <code>result</code> was infinite and <code>arg</code> was
+     *             not infinite
+     */
+    private static double exceptInf(double result, double arg) {
+        if (Double.isInfinite(result) && !Double.isInfinite(arg)) {
             throw Py.OverflowError("math range error");
+        } else {
+            return result;
         }
-        return v;
     }
 
     /**

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


More information about the Jython-checkins mailing list