diff options
Diffstat (limited to 'libjava/classpath/java/lang/StrictMath.java')
-rw-r--r-- | libjava/classpath/java/lang/StrictMath.java | 226 |
1 files changed, 190 insertions, 36 deletions
diff --git a/libjava/classpath/java/lang/StrictMath.java b/libjava/classpath/java/lang/StrictMath.java index 0f066216787..ec74ca4133b 100644 --- a/libjava/classpath/java/lang/StrictMath.java +++ b/libjava/classpath/java/lang/StrictMath.java @@ -633,6 +633,94 @@ public final strictfp class StrictMath } /** + * Returns the hyperbolic sine of <code>x</code> which is defined as + * (exp(x) - exp(-x)) / 2. + * + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is positive + * infinity.</li> + * <li>If the argument is negative infinity, the result is negative + * infinity.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>sinh</em> + * @return the hyperbolic sine of <code>x</code> + * + * @since 1.5 + */ + public static double sinh(double x) + { + // Method : + // mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + // 1. Replace x by |x| (sinh(-x) = -sinh(x)). + // 2. + // E + E/(E+1) + // 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) + // 2 + // + // 22 <= x <= lnovft : sinh(x) := exp(x)/2 + // lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) + // ln2ovft < x : sinh(x) := +inf (overflow) + + double t, w, h; + + long bits; + long h_bits; + long l_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.NEGATIVE_INFINITY; + + if (x < 0) + h = - 0.5; + else + h = 0.5; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ignore sign + l_bits = getLowDWord(bits); + + // |x| in [0, 22], return sign(x) * 0.5 * (E+E/(E+1)) + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3e300000L) // |x| < 2^-28 + return x; // for tiny arguments return x + + t = expm1(abs(x)); + + if (h_bits < 0x3ff00000L) + return h * (2.0 * t - t * t / (t + 1.0)); + + return h * (t + t / (t + 1.0)); + } + + // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) + if (h_bits < 0x40862e42L) + return h * exp(abs(x)); + + // |x| in [log(Double.MAX_VALUE), overflowthreshold] + if ((h_bits < 0x408633ceL) + || ((h_bits == 0x408633ceL) && (l_bits <= 0x8fb9f87dL))) + { + w = exp(0.5 * abs(x)); + t = h * w; + + return t * w; + } + + // |x| > overflowthershold + return h * Double.POSITIVE_INFINITY; + } + + /** * Returns the hyperbolic cosine of <code>x</code>, which is defined as * (exp(x) + exp(-x)) / 2. * @@ -670,36 +758,36 @@ public final strictfp class StrictMath double t, w; long bits; - int hx; - int lx; + long hx; + long lx; // handle special cases if (x != x) - return Double.NaN; + return x; if (x == Double.POSITIVE_INFINITY) return Double.POSITIVE_INFINITY; if (x == Double.NEGATIVE_INFINITY) return Double.POSITIVE_INFINITY; bits = Double.doubleToLongBits(x); - hx = getHighDWord(bits) & 0x7fffffff; // ignore sign + hx = getHighDWord(bits) & 0x7fffffffL; // ignore sign lx = getLowDWord(bits); // |x| in [0, 0.5 * ln(2)], return 1 + expm1(|x|)^2 / (2 * exp(|x|)) - if (hx < 0x3fd62e43) + if (hx < 0x3fd62e43L) { t = expm1(abs(x)); w = 1.0 + t; // for tiny arguments return 1. - if (hx < 0x3c800000) + if (hx < 0x3c800000L) return w; return 1.0 + (t * t) / (w + w); } // |x| in [0.5 * ln(2), 22], return exp(|x|)/2 + 1 / (2 * exp(|x|)) - if (hx < 0x40360000) + if (hx < 0x40360000L) { t = exp(abs(x)); @@ -707,16 +795,13 @@ public final strictfp class StrictMath } // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) - if (hx < 0x40862e42) + if (hx < 0x40862e42L) return 0.5 * exp(abs(x)); // |x| in [log(Double.MAX_VALUE), overflowthreshold], // return exp(x/2)/2 * exp(x/2) - - // we need to force an unsigned <= compare, thus can not use lx. - if ((hx < 0x408633ce) - || ((hx == 0x408633ce) - && ((bits & 0x00000000ffffffffL) <= 0x8fb9f87dL))) + if ((hx < 0x408633ceL) + || ((hx == 0x408633ceL) && (lx <= 0x8fb9f87dL))) { w = exp(0.5 * abs(x)); t = 0.5 * w; @@ -729,13 +814,82 @@ public final strictfp class StrictMath } /** + * Returns the hyperbolic tangent of <code>x</code>, which is defined as + * (exp(x) - exp(-x)) / (exp(x) + exp(-x)), i.e. sinh(x) / cosh(x). + * + Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is 1.</li> + * <li>If the argument is negative infinity, the result is -1.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>tanh</em> + * @return the hyperbolic tagent of <code>x</code> + * + * @since 1.5 + */ + public static double tanh(double x) + { + // Method : + // 0. tanh(x) is defined to be (exp(x) - exp(-x)) / (exp(x) + exp(-x)) + // 1. reduce x to non-negative by tanh(-x) = -tanh(x). + // 2. 0 <= x <= 2^-55 : tanh(x) := x * (1.0 + x) + // -t + // 2^-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x) + // t + 2 + // 2 + // 1 <= x <= 22.0 : tanh(x) := 1 - ----- ; t=expm1(2x) + // t + 2 + // 22.0 < x <= INF : tanh(x) := 1. + + double t, z; + + long bits; + long h_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return 1.0; + if (x == Double.NEGATIVE_INFINITY) + return -1.0; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ingnore sign + + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3c800000L) // |x| < 2^-55 + return x * (1.0 + x); + + if (h_bits >= 0x3ff00000L) // |x| >= 1 + { + t = expm1(2.0 * abs(x)); + z = 1.0 - 2.0 / (t + 2.0); + } + else // |x| < 1 + { + t = expm1(-2.0 * abs(x)); + z = -t / (t + 2.0); + } + } + else // |x| >= 22 + z = 1.0; + + return (x >= 0) ? z : -z; + } + + /** * Returns the lower two words of a long. This is intended to be * used like this: * <code>getLowDWord(Double.doubleToLongBits(x))</code>. */ - private static int getLowDWord(long x) + private static long getLowDWord(long x) { - return (int) (x & 0x00000000ffffffffL); + return x & 0x00000000ffffffffL; } /** @@ -743,19 +897,19 @@ public final strictfp class StrictMath * used like this: * <code>getHighDWord(Double.doubleToLongBits(x))</code>. */ - private static int getHighDWord(long x) + private static long getHighDWord(long x) { - return (int) ((x & 0xffffffff00000000L) >> 32); + return (x & 0xffffffff00000000L) >> 32; } /** * Returns a double with the IEEE754 bit pattern given in the lower * and higher two words <code>lowDWord</code> and <code>highDWord</code>. */ - private static double buildDouble(int lowDWord, int highDWord) + private static double buildDouble(long lowDWord, long highDWord) { - return Double.longBitsToDouble((((long) highDWord & 0xffffffffL) << 32) - | ((long) lowDWord & 0xffffffffL)); + return Double.longBitsToDouble(((highDWord & 0xffffffffL) << 32) + | (lowDWord & 0xffffffffL)); } /** @@ -788,12 +942,12 @@ public final strictfp class StrictMath double w; long bits; - int l; - int h; + long l; + long h; // handle the special cases if (x != x) - return Double.NaN; + return x; if (x == Double.POSITIVE_INFINITY) return Double.POSITIVE_INFINITY; if (x == Double.NEGATIVE_INFINITY) @@ -847,7 +1001,7 @@ public final strictfp class StrictMath s = t * t; // t * t is exact r = x / s; w = t + t; - r = (r - t) / (w + r); // r - s is exact + r = (r - t) / (w + r); // r - t is exact t = t + t * r; return negative ? -t : t; @@ -1008,8 +1162,8 @@ public final strictfp class StrictMath int k; long bits; - int h_bits; - int l_bits; + long h_bits; + long l_bits; c = 0.0; y = abs(x); @@ -1019,14 +1173,14 @@ public final strictfp class StrictMath l_bits = getLowDWord(bits); // handle special cases and large arguments - if (h_bits >= 0x4043687a) // if |x| >= 56 * ln(2) + if (h_bits >= 0x4043687aL) // if |x| >= 56 * ln(2) { - if (h_bits >= 0x40862e42) // if |x| >= EXP_LIMIT_H + if (h_bits >= 0x40862e42L) // if |x| >= EXP_LIMIT_H { - if (h_bits >= 0x7ff00000) + if (h_bits >= 0x7ff00000L) { - if (((h_bits & 0x000fffff) | (l_bits & 0xffffffff)) != 0) - return Double.NaN; // exp(NaN) = NaN + if (((h_bits & 0x000fffffL) | (l_bits & 0xffffffffL)) != 0) + return x; // exp(NaN) = NaN else return negative ? -1.0 : x; // exp({+-inf}) = {+inf, -1} } @@ -1040,9 +1194,9 @@ public final strictfp class StrictMath } // argument reduction - if (h_bits > 0x3fd62e42) // |x| > 0.5 * ln(2) + if (h_bits > 0x3fd62e42L) // |x| > 0.5 * ln(2) { - if (h_bits < 0x3ff0a2b2) // |x| < 1.5 * ln(2) + if (h_bits < 0x3ff0a2b2L) // |x| < 1.5 * ln(2) { if (negative) { @@ -1069,7 +1223,7 @@ public final strictfp class StrictMath c = (hi - x) - lo; } - else if (h_bits < 0x3c900000) // |x| < 2^-54 return x + else if (h_bits < 0x3c900000L) // |x| < 2^-54 return x return x; else k = 0; @@ -1124,7 +1278,7 @@ public final strictfp class StrictMath if (k < 20) { bits = Double.doubleToLongBits(t); - h_bits = 0x3ff00000 - (0x00200000 >> k); + h_bits = 0x3ff00000L - (0x00200000L >> k); l_bits = getLowDWord(bits); t = buildDouble(l_bits, h_bits); // t = 1 - 2^(-k) @@ -1141,7 +1295,7 @@ public final strictfp class StrictMath else { bits = Double.doubleToLongBits(t); - h_bits = (0x000003ff - k) << 20; + h_bits = (0x000003ffL - k) << 20; l_bits = getLowDWord(bits); t = buildDouble(l_bits, h_bits); // t = 2^(-k) |