// Copyright (c) Corporation for National Research Initiatives
package org.python.modules;
import org.python.core.ClassDictInit;
import org.python.core.Py;
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;
public class math implements ClassDictInit {
public static PyFloat pi = new PyFloat(Math.PI);
public static PyFloat e = new PyFloat(Math.E);
public static void classDictInit(PyObject dict) {
}
private static double check(double v) {
if (Double.isNaN(v))
throw Py.ValueError("math domain error");
if (Double.isInfinite(v))
throw Py.OverflowError("math range error");
return v;
}
public static double acos(double v) {
return check(Math.acos(v));
}
public static double asin(double v) {
return check(Math.asin(v));
}
public static double atan(double v) {
return check(Math.atan(v));
}
public static double atan2(double v, double w) {
return check(Math.atan2(v, w));
}
public static double ceil(double v) {
return check(Math.ceil(v));
}
public static double cos(double v) {
return check(Math.cos(v));
}
public static double exp(double v) {
return check(Math.exp(v));
}
public static double floor(PyObject v) {
return floor(v.asDouble());
}
public static double floor(double v) {
return check(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());
}
if (base != null) {
return check(applyLoggedBase(doubleValue, base));
}
return doubleValue;
}
private static double calculateLongLog(PyLong v) {
int e[] = new int[1];
double x = v.scaledDoubleValue(e);
if (x <= 0.0) throw Py.ValueError("math domain error");
return log(x) + (e[0]*8.0)*log(2.0);
}
private static double applyLoggedBase(double loggedValue, PyObject base) {
double loggedBase;
if (base instanceof PyLong) {
loggedBase = calculateLongLog((PyLong)base);
} else {
loggedBase = log(base.asDouble());
}
return check(loggedValue / loggedBase);
}
private static double log(double v) {
return check(Math.log(v));
}
public static double pow(double v, double w) {
return check(Math.pow(v, w));
}
public static double sin(PyObject v) {
return sin(v.asDouble());
}
public static double sin(double v) {
return check(Math.sin(v));
}
public static double sqrt(PyObject v) {
return sqrt(v.asDouble());
}
public static double sqrt(double v) {
return check(Math.sqrt(v));
}
public static double tan(double v) {
return check(Math.tan(v));
}
public static double log10(PyObject v) {
if (v instanceof PyLong) {
int e[] = new int[1];
double x = ((PyLong)v).scaledDoubleValue(e);
if (x <= 0.0) throw Py.ValueError("math domain error");
return log10(x) + (e[0]*8.0)*log10(2.0);
}
return log10(v.asDouble());
}
private static double log10(double v) {
return check(Math.log10(v));
}
public static double sinh(double v) {
return check(0.5 * (Math.exp(v) - Math.exp(-v)));
}
public static double cosh(double v) {
return check(0.5 * (Math.exp(v) + Math.exp(-v)));
}
public static double tanh(double v) {
return check(sinh(v) / cosh(v));
}
public static double fabs(double v) {
return Math.abs(v);
}
public static double fmod(double v, double w) {
return v % w;
}
public static PyTuple modf(double v) {
double w = v % 1.0;
v -= w;
return new PyTuple(new PyFloat(w), new PyFloat(v));
}
public static PyTuple frexp(double x) {
int exponent = 0;
if (Double.isNaN(x) || Double.isInfinite(x) || x == 0.0) {
exponent = 0;
} else {
short sign = 1;
if (x < 0.0) {
x = -x;
sign = -1;
}
for (; x < 0.5; x *= 2.0, exponent--);
for (; x >= 1.0; x *= 0.5, exponent++);
x *= sign;
}
return new PyTuple(new PyFloat(x), new PyInteger(exponent));
}
public static double ldexp(double v, PyObject wObj) {
int w = wObj.asInt();
return check(v * Math.pow(2.0, w));
}
public static double hypot(double v, double w) {
return check(Math.hypot(v, w));
}
public static double radians(double v) {
return check(Math.toRadians(v));
}
public static double degrees(double v) {
return check(Math.toDegrees(v));
}
}