summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Hao <jeffhao@google.com>2014-08-12 00:33:59 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2014-08-11 18:15:12 +0000
commit5fc90ef30f7c5c5864dae47a8c9f2ac557e62b0d (patch)
treec6ca8cb8ba9ff5c662052cf9a38ae6cd1646d53d
parentd6b99c6b1557584ca7e66e7365c08eae73d88ef4 (diff)
parent165e2b4075dadb99afc0856ab3c698809a6355a2 (diff)
downloadlibcore-5fc90ef30f7c5c5864dae47a8c9f2ac557e62b0d.zip
libcore-5fc90ef30f7c5c5864dae47a8c9f2ac557e62b0d.tar.gz
libcore-5fc90ef30f7c5c5864dae47a8c9f2ac557e62b0d.tar.bz2
Merge "Implements some StrictMath functions for improved performance."
-rw-r--r--luni/src/main/java/java/lang/StrictMath.java484
-rw-r--r--luni/src/main/native/java_lang_StrictMath.cpp30
2 files changed, 476 insertions, 38 deletions
diff --git a/luni/src/main/java/java/lang/StrictMath.java b/luni/src/main/java/java/lang/StrictMath.java
index 2e848f2..8d5d32d 100644
--- a/luni/src/main/java/java/lang/StrictMath.java
+++ b/luni/src/main/java/java/lang/StrictMath.java
@@ -16,7 +16,8 @@
*/
/*
- * acos, asin, atan, cosh, sinh, tanh, exp, expm1, log, log10, log1p, and cbrt
+ * acos, asin, atan, cosh, sinh, tanh, exp, expm1, log, log10, log1p, cbrt,
+ * ceil, floor, IEEEremainder, rint, nextafter, and hypot
* have been implemented with the following license.
* ====================================================
* Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
@@ -600,7 +601,71 @@ public final class StrictMath {
* <li>{@code ceil(NaN) = NaN}</li>
* </ul>
*/
- public static native double ceil(double d);
+ public static double ceil(double x) {
+ final long x_asRawLongBits = Double.doubleToRawLongBits(x);
+ int i0 = (int) (x_asRawLongBits >>> 32);
+ int i1 = (int) x_asRawLongBits;
+ final int j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+
+ if (j0 < 20) {
+ // Case where x is not zero.
+ if (j0 < 0) {
+ // Case where absolute value of x is less than 1.
+ if (HUGE + x > 0.0) {
+ if (i0 < 0) {
+ i0 = 0x80000000;
+ i1 = 0;
+ } else if ((i0 | i1) != 0) {
+ i0 = 0x3ff00000;
+ i1 = 0;
+ }
+ }
+ } else {
+ int i = (0x000fffff) >> j0;
+ if (((i0 & i) | i1) == 0) {
+ return x;
+ } else if (HUGE + x > 0.0) {
+ if (i0 > 0) {
+ i0 += (0x00100000) >> j0;
+ }
+ i0 &= (~i);
+ i1 = 0;
+ }
+ }
+ } else if (j0 > 51) {
+ if (j0 == 0x400) {
+ return x + x;
+ } else {
+ return x;
+ }
+ } else {
+ int i = (0xffffffff) >>> (j0 - 20);
+ if ((i1 & i) == 0) {
+ return x;
+ }
+ if (HUGE + x > 0.0) {
+ if (i0 > 0) {
+ if (j0 == 20) {
+ i0 += 1;
+ } else {
+ int j = i1 + (1 << (52 - j0));
+ if ((j ^ Integer.MIN_VALUE) < (i1 ^ Integer.MIN_VALUE)) {
+ // Carry value over for rounding purposes.
+ i0 += 1;
+ }
+ i1 = j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ x = Double.doubleToRawLongBits(i1);
+ long bits = Double.doubleToRawLongBits(x);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) i0) << 32;
+ x = Double.longBitsToDouble(bits);
+ return x;
+ }
private static final long ONEBITS = Double.doubleToRawLongBits(1.00000000000000000000e+00)
& 0x00000000ffffffffL;
@@ -820,7 +885,7 @@ public final class StrictMath {
xsb = highBits & 0x80000000; /* sign bit of x */
y = xsb == 0 ? x : -x; /* y = |x| */
- /* filter out huge and non-finite argument */
+ /* filter out HUGE and non-finite argument */
if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */
if (hx >= 0x40862E42) { /* if |x|>=709.78... */
if (hx >= 0x7ff00000) {
@@ -931,7 +996,72 @@ public final class StrictMath {
* <li>{@code floor(NaN) = NaN}</li>
* </ul>
*/
- public static native double floor(double d);
+ public static double floor(double x) {
+ final long x_asRawLongBits = Double.doubleToRawLongBits(x);
+ int i0 = (int) (x_asRawLongBits >>> 32);
+ int i1 = (int) x_asRawLongBits;
+ int j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+
+ if (j0 < 20) {
+ // Case where x is not zero.
+ if (j0 < 0) {
+ // Case where absolute value of x is less than 1.
+ if (HUGE + x > 0.0) {
+ if (i0 >= 0) {
+ i0 = 0;
+ i1 = 0;
+ } else if (((i0 & 0x7fffffff) | i1) != 0) {
+ i0 = 0xbff00000;
+ i1 = 0;
+ }
+ }
+ } else {
+ int i = (0x000fffff) >> j0;
+ if (((i0 & i) | i1) == 0) {
+ return x;
+ }
+ if (HUGE + x > 0.0) {
+ if (i0 < 0) {
+ i0 += (0x00100000) >> j0;
+ }
+ i0 &= (~i);
+ i1 = 0;
+ }
+ }
+ } else if (j0 > 51) {
+ if (j0 == 0x400) {
+ return x + x;
+ } else {
+ return x;
+ }
+ } else {
+ int i = (0xffffffff) >>> (j0 - 20);
+ if ((i1 & i) == 0) {
+ return x;
+ }
+ if (HUGE + x > 0.0) {
+ if (i0 < 0) {
+ if (j0 == 20) {
+ i0 += 1;
+ } else {
+ int j = i1 + (1 << (52 - j0));
+ if (j < i1) {
+ // Carry value over for rounding purposes.
+ i0 += 1;
+ }
+ i1 = j;
+ }
+ }
+ i1 &= (~i);
+ }
+ }
+ x = Double.doubleToRawLongBits(i1);
+ long bits = Double.doubleToRawLongBits(x);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) i0) << 32;
+ x = Double.longBitsToDouble(bits);
+ return x;
+ }
/**
* Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
@@ -955,7 +1085,134 @@ public final class StrictMath {
* <i> {@code y}</i><sup>{@code 2}</sup>{@code )} value of the
* arguments.
*/
- public static native double hypot(double x, double y);
+ public static double hypot(double x, double y) {
+ double a;
+ double b;
+ double t1;
+ double t2;
+ double y1;
+ double y2;
+ double w;
+ int j;
+ long bits;
+ x = StrictMath.abs(x);
+ y = StrictMath.abs(y);
+ // Convert x and y to long values for bitwise manipulation.
+ long x_asRawLongBits = Double.doubleToRawLongBits(x);
+ long y_asRawLongBits = Double.doubleToRawLongBits(y);
+ long ha = (x_asRawLongBits >> 32) & 0x7fffffff;
+ long hb = (y_asRawLongBits >> 32) & 0x7fffffff;
+ // Ensures that a is always the larger value.
+ if (hb > ha) {
+ a = y;
+ b = x;
+ j = (int) ha;
+ ha = hb;
+ hb = j;
+ } else {
+ a = x;
+ b = y;
+ }
+ // Deals with edge case where x is significantly larger than y.
+ if ((ha - hb) > 0x3c00000) {
+ if (a + b == Double.NEGATIVE_INFINITY) {
+ return Double.POSITIVE_INFINITY;
+ } else {
+ return a + b;
+ }
+ }
+ int k = 0;
+ // Deals with edge cases where numbers are infinite or invalid.
+ if (ha > 0x5f300000) {
+ if (ha >= 0x7ff00000) {
+ w = a + b;
+ if (((ha & 0xfffff) | Double.doubleToRawLongBits(a)) == 0) {
+ w = a;
+ }
+ if (((hb ^ 0x7ff00000) | Double.doubleToRawLongBits(b)) == 0) {
+ w = b;
+ }
+ return w;
+ }
+ // Scale a and b by 2**-600.
+ ha -= 0x25800000;
+ hb -= 0x25800000;
+ k += 600;
+ bits = Double.doubleToRawLongBits(a);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) ha) << 32;
+ a = Double.longBitsToDouble(bits);
+
+ bits = Double.doubleToRawLongBits(b);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) hb) << 32;
+ b = Double.longBitsToDouble(bits);
+ }
+ // Deals with cases where lesser number is abnormally small.
+ if (hb < 0x20b00000) {
+ if (hb <= 0x000fffff) {
+ if ((hb | (Double.doubleToRawLongBits(b))) == 0) {
+ return a;
+ }
+ t1 = 0;
+ bits = Double.doubleToRawLongBits(t1);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) 0x7fd00000) << 32;
+ t1 = Double.longBitsToDouble(bits);
+ b *= t1;
+ a *= t1;
+ k -= 1022;
+ } else {
+ ha += 0x25800000;
+ hb += 0x25800000;
+ k -= 600;
+ bits = Double.doubleToRawLongBits(a);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) ha) << 32;
+ a = Double.longBitsToDouble(bits);
+ bits = Double.doubleToRawLongBits(b);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) hb) << 32;
+ b = Double.longBitsToDouble(bits);
+ }
+ }
+ // Deals with cases where both numbers are not overly large or small.
+ w = a - b;
+ if (w > b) {
+ t1 = 0;
+ bits = Double.doubleToRawLongBits(t1);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) ha) << 32;
+ t1 = Double.longBitsToDouble(bits);
+ t2 = a - t1;
+ w = StrictMath.sqrt(t1 * t1 - (b * (-b) - t2 * (a + t1)));
+ } else {
+ a = a + a;
+ y1 = 0;
+ bits = Double.doubleToRawLongBits(y1);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) hb) << 32;
+ y1 = Double.longBitsToDouble(bits);
+ y2 = b - y1;
+ t1 = 0;
+ bits = Double.doubleToRawLongBits(t1);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) ha + 0x00100000) << 32;
+ t1 = Double.longBitsToDouble(bits);
+ t2 = a - t1;
+ w = StrictMath.sqrt(t1 * y1 - (w * (-w) - (t1 * y2 + t2 * b)));
+ }
+ if (k != 0) {
+ t1 = 1.0;
+ bits = Double.doubleToRawLongBits(t1);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) (k << 20)) << 32;
+ t1 = Double.longBitsToDouble(bits);
+ return t1 * w;
+ } else {
+ return w;
+ }
+ }
/**
* Returns the remainder of dividing {@code x} by {@code y} using the IEEE
@@ -982,7 +1239,72 @@ public final class StrictMath {
* the denominator of the operation.
* @return the IEEE754 floating point reminder of of {@code x/y}.
*/
- public static native double IEEEremainder(double x, double y);
+ public static double IEEEremainder(double x, double y) {
+ final double zero = 0.0;
+ // Convert x and y to long data types.
+ final long x_asRawLongBits = Double.doubleToRawLongBits(x);
+ int hx = (int) (x_asRawLongBits >>> 32);
+ int lx = (int) x_asRawLongBits;
+ final long y_asRawLongBits = Double.doubleToRawLongBits(y);
+ int hy = (int) (y_asRawLongBits >>> 32);
+ int ly = (int) y_asRawLongBits;
+ long sx = hx & 0x80000000;
+ hy &= 0x7fffffff;
+ hx &= 0x7fffffff;
+
+ // Deals with edge cases like y = 0 and x or y is NaN.
+ if ((hy | ly) == 0) {
+ return (x * y) / (x * y);
+ }
+ if ((hx >= 0x7ff00000) || ((hy >= 0x7ff00000) && (((hy - 0x7ff00000) | ly) != 0))) {
+ return (x * y) / (x * y);
+ }
+ if (hy <= 0x7fdfffff) {
+ x = x % (y + y);
+ }
+ if (((hx - hy) | (lx - ly)) == 0) {
+ return zero * x;
+ }
+
+ // Ensures positive remainders are returned.
+ double x1 = x;
+ double y1 = y;
+ x = StrictMath.abs(x);
+ y = StrictMath.abs(y);
+ double z = x;
+ if (hy < 0x00200000) {
+ if (x + x > y) {
+ z -= y;
+ if (z + z >= y) {
+ z -= y;
+ }
+ }
+ } else {
+ double y_half = 0.5 * y;
+ if (x > y_half) {
+ z -= y;
+ if (z >= y_half) {
+ z -= y;
+ }
+ }
+ }
+
+ long bits = Double.doubleToRawLongBits(z);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) (sx)) << 32;
+ z = Double.longBitsToDouble(bits);
+
+ if (x < y && x1 < 0) {
+ if ((y - x) < x) {
+ z *= -1;
+ }
+ } else if (x >= y && x1 < 0) {
+ if ((x - y) > y / 2) {
+ z *= -1;
+ }
+ }
+ return z;
+ }
private static final double LG1 = 6.666666666666735130e-01;
private static final double LG2 = 3.999999999940941908e-01;
@@ -1485,7 +1807,87 @@ public final class StrictMath {
* the value to be rounded.
* @return the closest integer to the argument (as a double).
*/
- public static native double rint(double d);
+ public static double rint(double x) {
+ double w;
+ double t;
+ long bits;
+ // Magic numbers from the fdlibm code.
+ double m0 = 4.50359962737049600000e+15;
+ double m1 = -4.50359962737049600000e+15;
+
+ // Converting x to a long type for bitwise operations.
+ final long x_asRawLongBits = Double.doubleToRawLongBits(x);
+ int i0 = (int) (x_asRawLongBits >>> 32);
+ int i1 = (int) x_asRawLongBits;
+ int sx = (i0 >> 31) & 1;
+ int j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+
+ if (j0 < 20) {
+ if (j0 < 0) {
+ if (((i0 & 0x7fffffff) | i1) == 0) {
+ return x;
+ }
+ i1 |= (i0 & 0x0fffff);
+ i0 &= 0xfffe0000;
+ i0 |= ((i1 | -i1) >> 12) & 0x80000;
+
+ // Convert x to long and replace its upper bits with i0.
+ bits = Double.doubleToRawLongBits(x);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) (i0)) << 32;
+ x = Double.longBitsToDouble(bits);
+
+ if (sx == 0) {
+ w = m0 + x;
+ t = w - m0;
+ } else {
+ w = m1 + x;
+ t = w - m1;
+ }
+ i0 = (int) (Double.doubleToRawLongBits(t) >>> 32);
+ bits = Double.doubleToRawLongBits(t);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) ((i0 & 0x7fffffff) | (sx << 31))) << 32;
+ t = Double.longBitsToDouble(bits);
+ return t;
+ } else {
+ int i = (0x000fffff) >> j0;
+ if (((i0 & i) | i1) == 0) {
+ return x;
+ }
+ i >>= 1;
+ if (((i0 & i) | i1) != 0) {
+ if (j0 == 19) {
+ i1 = 0x40000000;
+ } else {
+ i0 = (i0 & (~i)) | ((0x20000) >> j0);
+ }
+ }
+ }
+ } else if (j0 > 51) {
+ if (j0 == 0x400) {
+ return x + x;
+ } else {
+ return x;
+ }
+ } else {
+ int i = ((int) (0xffffffff)) >> (j0 - 20);
+ if ((i1 & i) == 0) {
+ return x;
+ }
+ i >>= 1;
+ if ((i1 & i) != 0) {
+ i1 = (i1 & (~i)) | ((0x40000000) >> (j0 - 20));
+ }
+ }
+ if (sx == 0) {
+ w = m0 + x;
+ return w - m0;
+ } else {
+ w = m1 + x;
+ return w - m1;
+ }
+ }
/**
* Returns the result of rounding the argument to an integer. The result is
@@ -1847,7 +2249,73 @@ public final class StrictMath {
return Math.ulp(f);
}
- private static native double nextafter(double x, double y);
+ /**
+ * Returns the next machine floating-point number of x in the direction
+ * toward y.
+ */
+ private static double nextafter(double x, double y) {
+ double small = 1.4e-45;
+ long bits;
+ boolean raise = false;
+ boolean lower = false;
+ final long x_asRawLongBits = Double.doubleToRawLongBits(x);
+ final long y_asRawLongBits = Double.doubleToRawLongBits(y);
+ int hx = (int) x_asRawLongBits;
+ int lx = ((int) (x_asRawLongBits >>> 32)) & 0x7fffffff;
+ int hy = (int) y_asRawLongBits;
+ int ly = ((int) (y_asRawLongBits >>> 32)) & 0x7fffffff;
+ int ix = hx & 0x7fffffff;
+ int iy = hy & 0x7fffffff;
+ // Deals with edge cases where x and y are 0, invalid, or equal.
+ if (Double.isNaN(x) || Double.isNaN(y)) {
+ return Double.NaN;
+ }
+ if (x == y) {
+ return x;
+ }
+ if ((ix | lx) == 0) {
+ return small;
+ }
+ // Sets boolean to adjust return value depending on the signs of x and y.
+ if (x >= 0) {
+ if (x > y || ((hx == hy) && (lx > ly))) {
+ lower = true;
+ } else {
+ raise = true;
+ }
+ } else {
+ if (x > y || ((hx == hy) && (lx > ly))) {
+ raise = true;
+ } else {
+ lower = true;
+ }
+ }
+ hy = hx & 0x7ff00000;
+ if (hy >= 0x7ff00000) {
+ return x + x;
+ }
+ if (hy < 0x00100000) {
+ y = x * x;
+ if (y != x) {
+ bits = Double.doubleToRawLongBits(y);
+ bits &= 0x00000000FFFFFFFF;
+ bits |= ((long) (hy)) << 32;
+ y = Double.longBitsToDouble(bits);
+ return y;
+ }
+ }
+ // Adjust the return value if necessary.
+ bits = Double.doubleToRawLongBits(x);
+ bits &= 0x00000000FFFFFFFF;
+ if (lower) {
+ bits -= 1;
+ }
+ if (raise) {
+ bits += 1;
+ }
+ x = Double.longBitsToDouble(bits);
+ return x;
+ }
/**
* Returns a double with the given magnitude and the sign of {@code sign}.
diff --git a/luni/src/main/native/java_lang_StrictMath.cpp b/luni/src/main/native/java_lang_StrictMath.cpp
index e8c6dfb..972e272 100644
--- a/luni/src/main/native/java_lang_StrictMath.cpp
+++ b/luni/src/main/native/java_lang_StrictMath.cpp
@@ -38,43 +38,13 @@ static jdouble StrictMath_sqrt(JNIEnv*, jclass, jdouble a) {
return ieee_sqrt(a);
}
-static jdouble StrictMath_IEEEremainder(JNIEnv*, jclass, jdouble a, jdouble b) {
- return ieee_remainder(a, b);
-}
-
-static jdouble StrictMath_floor(JNIEnv*, jclass, jdouble a) {
- return ieee_floor(a);
-}
-
-static jdouble StrictMath_ceil(JNIEnv*, jclass, jdouble a) {
- return ieee_ceil(a);
-}
-
-static jdouble StrictMath_rint(JNIEnv*, jclass, jdouble a) {
- return ieee_rint(a);
-}
-
static jdouble StrictMath_pow(JNIEnv*, jclass, jdouble a, jdouble b) {
return ieee_pow(a,b);
}
-static jdouble StrictMath_hypot(JNIEnv*, jclass, jdouble a, jdouble b) {
- return ieee_hypot(a, b);
-}
-
-static jdouble StrictMath_nextafter(JNIEnv*, jclass, jdouble a, jdouble b) {
- return ieee_nextafter(a, b);
-}
-
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(StrictMath, IEEEremainder, "!(DD)D"),
- NATIVE_METHOD(StrictMath, ceil, "!(D)D"),
NATIVE_METHOD(StrictMath, cos, "!(D)D"),
- NATIVE_METHOD(StrictMath, floor, "!(D)D"),
- NATIVE_METHOD(StrictMath, hypot, "!(DD)D"),
- NATIVE_METHOD(StrictMath, nextafter, "!(DD)D"),
NATIVE_METHOD(StrictMath, pow, "!(DD)D"),
- NATIVE_METHOD(StrictMath, rint, "!(D)D"),
NATIVE_METHOD(StrictMath, sin, "!(D)D"),
NATIVE_METHOD(StrictMath, sqrt, "!(D)D"),
NATIVE_METHOD(StrictMath, tan, "!(D)D"),