// Copyright (c) Corporation for National Research Initiatives package org.python.modules; import java.math.BigInteger; import org.python.core.ClassDictInit; import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyFloat; import org.python.core.PyInteger; import org.python.core.PyLong; import org.python.core.PyObject; import org.python.core.PyTuple; import org.python.core.__builtin__; public class math implements ClassDictInit { public static PyFloat pi = new PyFloat(Math.PI); public static PyFloat e = new PyFloat(Math.E); private static final double ZERO = 0.0; private static final double MINUS_ZERO = -0.0; private static final double ONE = 1.0; private static final double MINUS_ONE = -1.0; private static final double TWO = 2.0; private static final double EIGHT = 8.0; static final double LN2 = 0.693147180559945309417232121458; // Ref OEIS A002162 private static final double INF = Double.POSITIVE_INFINITY; private static final double NINF = Double.NEGATIVE_INFINITY; private static final double NAN = Double.NaN; private static final BigInteger MAX_LONG_BIGINTEGER = new BigInteger( String.valueOf(Long.MAX_VALUE)); private static final BigInteger MIN_LONG_BIGINTEGER = new BigInteger( String.valueOf(Long.MIN_VALUE)); public static void classDictInit(@SuppressWarnings("unused") PyObject dict) {} public static double gamma(double v) { return math_gamma.gamma(v); } public static double lgamma(double v) { return math_gamma.lgamma(v); } public static double erf(double v) { return math_erf.erf(v); } public static double erfc(double v) { return math_erf.erfc(v); } public static double expm1(double v) { if (Double.POSITIVE_INFINITY == v) { return v; } double result = Math.expm1(v); if (Double.isInfinite(result)) { throw Py.OverflowError(Double.toString(v)); } return result; } public static double acos(double v) { return exceptNaN(Math.acos(v), v); } /** * Compute cosh-1y. * * @param y * @return x such that cosh x = y */ public static double acosh(double y) { if (y < 1.0) { throw mathDomainError(); } else { // acosh(y) = ln[y + sqrt(y**2 - 1)] if (y < 2.) { // Rearrange as acosh(1+u) = ln[1 + u + sqrt(u(2+u))] final double u = y - 1.; double s = Math.sqrt(u * (2. + u)); return Math.log1p(u + s); } else if (y < 0x1p27) { // Rearrange as acosh(y) = ln[ y ( 1 + sqrt[1-(1/y)**2] )] final double u = 1. / y; double t = Math.sqrt((1. + u) * (1. - u)); return Math.log(y * (1. + t)); } else { // As above but t indistinguishable from 1.0 so ... return Math.log(y) + LN2; } } } public static double asin(double v) { return exceptNaN(Math.asin(v), v); } public static double asinh(double v) { if (isnan(v) || isinf(v)) { return v; } final double ln2 = 6.93147180559945286227e-01; final double large = 1 << 28; final double small = 1.0 / (1 << 28); boolean sign = false; if (v < 0) { v = -v; sign = true; } double temp; if (v > large) { temp = log(v) + ln2; } else if (v > 2) { temp = log(2 * v + 1 / (sqrt(v * v + 1) + v)); } else if (v < small) { temp = v; } else { temp = log1p(v + v * v / (1 + sqrt(1 + v * v))); } return sign ? -temp : temp; } public static double atan(double v) { return exceptNaN(Math.atan(v), v); } /** * Compute tanh-1y. * * @param y * @return x such that tanh x = y */ public static double atanh(double y) { double absy = Math.abs(y); if (absy >= 1.0) { throw mathDomainError(); } else { // 2x = ln[(1+y)/(1-y)] = ln[1 + 2y/(1-y)] double u = (absy + absy) / (1. - absy); double x = 0.5 * Math.log1p(u); return Math.copySign(x, y); } } public static double atan2(double v, double w) { return Math.atan2(v, w); } public static double ceil(PyObject v) { return ceil(v.asDouble()); } public static double ceil(double v) { return Math.ceil(v); } public static double cos(double v) { return exceptNaN(Math.cos(v), v); } public static double cosh(double v) { return exceptInf(Math.cosh(v), v); } public static double exp(double v) { return exceptInf(Math.exp(v), v); } public static double floor(PyObject v) { return floor(v.asDouble()); } public static double floor(double v) { return Math.floor(v); } public static double log(PyObject v) { return log(v, null); } public static double log(PyObject v, PyObject base) { double doubleValue; if (v instanceof PyLong) { doubleValue = calculateLongLog((PyLong)v); } else { doubleValue = log(v.asDouble()); } return (base == null) ? doubleValue : applyLoggedBase(doubleValue, base); } public static double pow(double v, double w) { if (w == ZERO) { return ONE; } if (v == ONE) { return v; } if (isnan(v) || isnan(w)) { return NAN; } if (v == ZERO) { if (w == ZERO) { return ONE; } else if (w > ZERO || ispinf(w)) { return ZERO; } else { throw mathDomainError(); } } if (isninf(v)) { if (isninf(w)) { return ZERO; } if (isinf(w)) { return INF; } if (w == ZERO) { return ONE; } if (w > ZERO) { if (isOdd(w)) { return NINF; } return INF; } if (isOdd(w)) { return MINUS_ZERO; } return ZERO; } if (isninf(w)) { if (v < ZERO) { if (v == MINUS_ONE) { return ONE; } if (v < MINUS_ONE) { return ZERO; } return INF; } } if (ispinf(w)) { if (v < ZERO) { if (v == MINUS_ONE) { return ONE; } if (v < MINUS_ONE) { return INF; } return ZERO; } } if (v < ZERO && !isIntegral(w)) { throw mathDomainError(); } return Math.pow(v, w); } public static double sin(PyObject v) { return sin(v.asDouble()); } public static double sin(double v) { return exceptNaN(Math.sin(v), v); } public static double sqrt(PyObject v) { return sqrt(v.asDouble()); } public static double sqrt(double v) { return exceptNaN(Math.sqrt(v), v); } public static double tan(double v) { return exceptNaN(Math.tan(v), v); } public static double log10(PyObject v) { if (v instanceof PyLong) { int exp[] = new int[1]; double x = ((PyLong)v).scaledDoubleValue(exp); if (x <= ZERO) { throw mathDomainError(); } return log10(x) + (exp[0] * EIGHT) * log10(TWO); } return log10(v.asDouble()); } public static double sinh(double v) { return exceptInf(Math.sinh(v), v); } public static double tanh(double v) { return exceptInf(Math.tanh(v), v); } public static double fabs(double v) { return Math.abs(v); } public static double fmod(double v, double w) { if (isnan(v) || isnan(w)) { return NAN; } if (isinf(w)) { return v; } if (w == ZERO) { throw mathDomainError(); } if (isinf(v) && w == ONE) { throw mathDomainError(); } return v % w; } public static PyTuple modf(double v) { if (isnan(v)) { return new PyTuple(new PyFloat(v), new PyFloat(v)); } if (isinf(v)) { double first = ZERO; if (isninf(v)) { first = MINUS_ZERO; } return new PyTuple(new PyFloat(first), new PyFloat(v)); } double w = v % ONE; v -= w; return new PyTuple(new PyFloat(w), new PyFloat(v)); } public static PyTuple frexp(double x) { int exponent; double mantissa; switch (exponent = Math.getExponent(x)) { default: // x = m * 2**exponent and 1 <=abs(m) <2 exponent = exponent + 1; // x = m * 2**exponent and 0.5 <=abs(m) <1 mantissa = Math.scalb(x, -exponent); break; case 1024: // nan or inf mantissa = x; exponent = 0; break; case -1023: if (x == 0.) { // , 0.0 or -0.0 mantissa = x; exponent = 0; } else { // denormalised value // x = m * 2**exponent but 0 < abs(m) < 1 exponent = Math.getExponent(x * 0x1p52) - 51; mantissa = Math.scalb(x, -exponent); } break; } return new PyTuple(new PyFloat(mantissa), new PyInteger(exponent)); } public static PyObject trunc(PyObject number) { return number.__getattr__("__trunc__").__call__(); } public static double ldexp(double v, PyObject wObj) { long w = getLong(wObj); if (w < Integer.MIN_VALUE) { w = Integer.MIN_VALUE; } else if (w > Integer.MAX_VALUE) { w = Integer.MAX_VALUE; } return exceptInf(Math.scalb(v, (int)w), v); } /** * Returns (x2 +y2)½ without intermediate overflow or * underflow. If either argument is infinite, the result is infinite, but overflow during the * calculation is detected as an error. * * @param x * @param y * @return (x2 +y2)½ */ public static double hypot(double x, double y) { double mag = Math.hypot(x, y); if (Double.isInfinite(mag) && !(Double.isInfinite(x) || Double.isInfinite(y))) { // In these circumstances Math.hypot quietly returns inf, but CPython should raise. throw mathRangeError(); } return mag; } public static double radians(double v) { return Math.toRadians(v); } public static double degrees(double 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) { return Double.isNaN(v); } /** * @param v * * @return true if v is positive or negative infinity */ public static boolean isinf(double v) { return Double.isInfinite(v); } public static double copysign(double v, double w) { return Math.copySign(v, w); } 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); } } public static double log1p(double v) { if (v <= -1.) { throw mathDomainError(); } else { return Math.log1p(v); } } public static double fsum(final PyObject iterable) { PyFloat result = (PyFloat)__builtin__.__import__("_fsum").invoke("fsum", iterable); return result.asDouble(); } private static double calculateLongLog(PyLong v) { int exp[] = new int[1]; double x = v.scaledDoubleValue(exp); if (x <= ZERO) { throw mathDomainError(); } return log(x) + (exp[0] * EIGHT) * log(TWO); } private static double applyLoggedBase(double loggedValue, PyObject base) { double loggedBase; if (base instanceof PyLong) { loggedBase = calculateLongLog((PyLong)base); } else { loggedBase = log(base.asDouble()); } return loggedValue / loggedBase; } private static double log(double v) { if (v <= 0.) { throw mathDomainError(); } else { return Math.log(v); } } private static double log10(double v) { if (v <= 0.) { throw mathDomainError(); } else { return Math.log10(v); } } private static boolean isninf(double v) { return v == NINF; } private static boolean ispinf(double v) { return v == INF; } /** * Returns a ValueError("math domain error"), ready to throw from the client code. * * @return ValueError("math domain error") */ static PyException mathDomainError() { return Py.ValueError("math domain error"); } /** * Returns a OverflowError("math range error"), ready to throw from the client code. * * @return OverflowError("math range error") */ static PyException mathRangeError() { return Py.OverflowError("math range error"); } /** * Turn a NaN result into a thrown ValueError, a math domain error, if * the original argument was not itself NaN. Use as: * *
     * public static double asin(double v) { return exceptNaN(Math.asin(v), v); }
     * 
* * 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 ValueError. This is a brief way to change that. * * @param result to return (if we return) * @param arg to include in check * @return result if arg was NaN or result was not * NaN * @throws PyException {@code ValueError} if result was NaN and * arg was not NaN */ 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 OverflowError, a math range error, if the * original argument was not itself infinite. Use as: * *
     * public static double cosh(double v) { return exceptInf( Math.cosh(v), v); }
     * 
* * 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 OverflowError. This is a brief way to change that. * * @param result to return (if we return) * @param arg to include in check * @return result if arg was infinite or result was not infinite * @throws PyException {@code ValueError} if result was infinite and * arg was not infinite */ private static double exceptInf(double result, double arg) { if (Double.isInfinite(result) && !Double.isInfinite(arg)) { throw mathRangeError(); } else { return result; } } /** * convert a PyObject into a long between Long.MIN_VALUE and Long.MAX_VALUE */ private static long getLong(PyObject pyo) { if (pyo instanceof PyLong) { return getLong(((PyLong)pyo)); } return pyo.asLong(); } /** * convert a PyLong into a long between Long.MIN_VALUE and Long.MAX_VALUE */ private static long getLong(PyLong pyLong) { BigInteger value = pyLong.getValue(); if (value.compareTo(MAX_LONG_BIGINTEGER) > 0) { return Long.MAX_VALUE; } if (value.compareTo(MIN_LONG_BIGINTEGER) < 0) { return Long.MIN_VALUE; } return value.longValue(); } private static boolean isIntegral(double v) { return ceil(v) - v == ZERO; } private static boolean isOdd(double v) { return isIntegral(v) && v % TWO != ZERO; } }