src.org.python.modules.math Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jython Show documentation
Show all versions of jython Show documentation
Jython is an implementation of the high-level, dynamic, object-oriented
language Python written in 100% Pure Java, and seamlessly integrated with
the Java platform. It thus allows you to run Python on any Java platform.
// 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;
}
}