[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