blob: 82463fa90cb6a742c07b74c4725c6a4310044534 [file] [log] [blame]
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package java.lang;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;
/**
* Math utility methods and constants.
*/
public final class Math {
// The following methods are not implemented because JS doesn't provide the
// necessary pieces:
// public static double ulp (double x)
// public static float ulp (float x)
// public static int getExponent (double d)
// public static int getExponent (float f)
// public static double IEEEremainder(double f1, double f2)
// public static double nextAfter(double start, double direction)
// public static float nextAfter(float start, float direction)
// public static double nextUp(double start) {
// return nextAfter(start, 1.0d);
// }
// public static float nextUp(float start) {
// return nextAfter(start,1.0f);
// }
public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;
private static final double PI_OVER_180 = PI / 180.0;
private static final double PI_UNDER_180 = 180.0 / PI;
public static double abs(double x) {
// This is implemented this way so that either positive or negative zeroes
// get converted to positive zeros.
// See http://www.concentric.net/~Ttwang/tech/javafloat.htm for details.
return x <= 0 ? 0.0 - x : x;
}
public static float abs(float x) {
return (float) abs((double) x);
}
public static int abs(int x) {
return x < 0 ? -x : x;
}
public static long abs(long x) {
return x < 0 ? -x : x;
}
public static double acos(double x) {
return NativeMath.acos(x);
}
public static double asin(double x) {
return NativeMath.asin(x);
}
public static int addExact(int x, int y) {
int r = x + y;
// "Hacker's Delight" 2-12 Overflow if both arguments have the opposite sign of the result
throwOverflowIf(((x ^ r) & (y ^ r)) < 0);
return r;
}
public static long addExact(long x, long y) {
long r = x + y;
// "Hacker's Delight" 2-12 Overflow if both arguments have the opposite sign of the result
throwOverflowIf(((x ^ r) & (y ^ r)) < 0);
return r;
}
public static double atan(double x) {
return NativeMath.atan(x);
}
public static double atan2(double y, double x) {
return NativeMath.atan2(y, x);
}
public static double cbrt(double x) {
return Math.pow(x, 1.0 / 3.0);
}
public static double ceil(double x) {
return NativeMath.ceil(x);
}
public static double copySign(double magnitude, double sign) {
if (sign < 0) {
return (magnitude < 0) ? magnitude : -magnitude;
} else {
return (magnitude > 0) ? magnitude : -magnitude;
}
}
public static float copySign(float magnitude, float sign) {
return (float) (copySign((double) magnitude, (double) sign));
}
public static double cos(double x) {
return NativeMath.cos(x);
}
public static double cosh(double x) {
return (Math.exp(x) + Math.exp(-x)) / 2.0;
}
public static int decrementExact(int x) {
throwOverflowIf(x == Integer.MIN_VALUE);
return x - 1;
}
public static long decrementExact(long x) {
throwOverflowIf(x == Long.MIN_VALUE);
return x - 1;
}
public static double exp(double x) {
return NativeMath.exp(x);
}
public static double expm1(double d) {
if (d == 0.0 || Double.isNaN(d)) {
return d; // "a zero with same sign as argument", arg is zero, so...
} else if (!Double.isInfinite(d)) {
if (d < 0.0d) {
return -1.0d;
} else {
return Double.POSITIVE_INFINITY;
}
}
return exp(d) + 1.0d;
}
public static double floor(double x) {
return NativeMath.floor(x);
}
public static int floorDiv(int dividend, int divisor) {
throwDivByZeroIf(divisor == 0);
int r = dividend / divisor;
// if the signs are different and modulo not zero, round down
if ((dividend ^ divisor) < 0 && (r * divisor != dividend)) {
r--;
}
return r;
}
public static long floorDiv(long dividend, long divisor) {
throwDivByZeroIf(divisor == 0);
long r = dividend / divisor;
// if the signs are different and modulo not zero, round down
if ((dividend ^ divisor) < 0 && (r * divisor != dividend)) {
r--;
}
return r;
}
public static int floorMod(int dividend, int divisor) {
return dividend - floorDiv(dividend, divisor) * divisor;
}
public static long floorMod(long dividend, long divisor) {
return dividend - floorDiv(dividend, divisor) * divisor;
}
public static double hypot(double x, double y) {
return sqrt(x * x + y * y);
}
public static int incrementExact(int x) {
throwOverflowIf(x == Integer.MAX_VALUE);
return x + 1;
}
public static long incrementExact(long x) {
throwOverflowIf(x == Long.MAX_VALUE);
return x + 1;
}
public static double log(double x) {
return NativeMath.log(x);
}
public static double log10(double x) {
return NativeMath.log(x) * NativeMath.LOG10E;
}
public static double log1p(double x) {
return Math.log(x + 1.0d);
}
public static double max(double x, double y) {
return NativeMath.max(x, y);
}
public static float max(float x, float y) {
return (float) NativeMath.max(x, y);
}
public static int max(int x, int y) {
return x > y ? x : y;
}
public static long max(long x, long y) {
return x > y ? x : y;
}
public static double min(double x, double y) {
return NativeMath.min(x, y);
}
public static float min(float x, float y) {
return (float) NativeMath.min(x, y);
}
public static int min(int x, int y) {
return x < y ? x : y;
}
public static long min(long x, long y) {
return x < y ? x : y;
}
public static int multiplyExact(int x, int y) {
long r = (long) x * (long) y;
int ir = (int) r;
throwOverflowIf(ir != r);
return ir;
}
public static long multiplyExact(long x, long y) {
long r = x * y;
throwOverflowIf((x == Long.MIN_VALUE && y == -1) || (y != 0 && (r / y != x)));
return r;
}
public static int negateExact(int x) {
throwOverflowIf(x == Integer.MIN_VALUE);
return -x;
}
public static long negateExact(long x) {
throwOverflowIf(x == Long.MIN_VALUE);
return -x;
}
public static double pow(double x, double exp) {
return NativeMath.pow(x, exp);
}
public static double random() {
return NativeMath.random();
}
public static double rint(double x) {
double mod2 = x % 2;
if ((mod2 == -1.5) || (mod2 == 0.5)) {
return NativeMath.floor(x);
} else {
return NativeMath.round(x);
}
}
public static long round(double x) {
return (long) NativeMath.round(x);
}
public static int round(float x) {
double roundedValue = NativeMath.round(x);
return unsafeCastToInt(roundedValue);
}
private static native int unsafeCastToInt(double d) /*-{
return d;
}-*/;
public static int subtractExact(int x, int y) {
int r = x - y;
// "Hacker's Delight" Overflow if the arguments have different signs and
// the sign of the result is different than the sign of x
throwOverflowIf(((x ^ y) & (x ^ r)) < 0);
return r;
}
public static long subtractExact(long x, long y) {
long r = x - y;
// "Hacker's Delight" Overflow if the arguments have different signs and
// the sign of the result is different than the sign of x
throwOverflowIf(((x ^ y) & (x ^ r)) < 0);
return r;
}
public static double scalb(double d, int scaleFactor) {
if (scaleFactor >= 31 || scaleFactor <= -31) {
return d * Math.pow(2, scaleFactor);
} else if (scaleFactor > 0) {
return d * (1 << scaleFactor);
} else if (scaleFactor == 0) {
return d;
} else {
return d * 1.0d / (1 << -scaleFactor);
}
}
public static float scalb(float f, int scaleFactor) {
return (float) scalb((double) f, scaleFactor);
}
public static double signum(double d) {
if (d == 0. || Double.isNaN(d)) {
return d;
} else {
return d < 0 ? -1 : 1;
}
}
public static float signum(float f) {
return (float) signum((double) f);
}
public static double sin(double x) {
return NativeMath.sin(x);
}
public static double sinh(double x) {
return (Math.exp(x) - Math.exp(-x)) / 2.0d;
}
public static double sqrt(double x) {
return NativeMath.sqrt(x);
}
public static double tan(double x) {
return NativeMath.tan(x);
}
public static double tanh(double x) {
if (Double.isInfinite(x)) {
return signum(x);
}
double e2x = Math.exp(2.0 * x);
return (e2x - 1) / (e2x + 1);
}
public static double toDegrees(double x) {
return x * PI_UNDER_180;
}
public static int toIntExact(long x) {
int ix = (int) x;
throwOverflowIf(ix != x);
return ix;
}
public static double toRadians(double x) {
return x * PI_OVER_180;
}
private static void throwDivByZeroIf(boolean condition) {
if (condition) {
throw new ArithmeticException("div by zero");
}
}
private static void throwOverflowIf(boolean condition) {
if (condition) {
throw new ArithmeticException("overflow");
}
}
@JsType(isNative = true, name = "Math", namespace = JsPackage.GLOBAL)
private static class NativeMath {
public static double LOG10E;
public static native double acos(double x);
public static native double asin(double x);
public static native double atan(double x);
public static native double atan2(double y, double x);
public static native double ceil(double x);
public static native double cos(double x);
public static native double exp(double x);
public static native double floor(double x);
public static native double log(double x);
public static native double max(double x, double y);
public static native double min(double x, double y);
public static native double pow(double x, double exp);
public static native double random();
public static native double round(double x);
public static native double sin(double x);
public static native double sqrt(double x);
public static native double tan(double x);
}
}