mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8301444: Port fdlibm hyperbolic transcendental functions to Java
Reviewed-by: bpb
This commit is contained in:
parent
b242eef93e
commit
655a71277d
6 changed files with 656 additions and 50 deletions
|
@ -950,8 +950,9 @@ class FdLibm {
|
||||||
* compiler will convert from decimal to binary accurately enough
|
* compiler will convert from decimal to binary accurately enough
|
||||||
* to produce the hexadecimal values shown.
|
* to produce the hexadecimal values shown.
|
||||||
*/
|
*/
|
||||||
static class Exp {
|
static final class Exp {
|
||||||
private static final double one = 1.0;
|
private Exp() {throw new UnsupportedOperationException();}
|
||||||
|
|
||||||
private static final double[] half = {0.5, -0.5,};
|
private static final double[] half = {0.5, -0.5,};
|
||||||
private static final double huge = 1.0e+300;
|
private static final double huge = 1.0e+300;
|
||||||
private static final double twom1000= 0x1.0p-1000; // 9.33263618503218878990e-302 = 2^-1000
|
private static final double twom1000= 0x1.0p-1000; // 9.33263618503218878990e-302 = 2^-1000
|
||||||
|
@ -969,10 +970,6 @@ class FdLibm {
|
||||||
private static final double P4 = -0x1.bbd41c5d26bf1p-20; // -1.65339022054652515390e-06
|
private static final double P4 = -0x1.bbd41c5d26bf1p-20; // -1.65339022054652515390e-06
|
||||||
private static final double P5 = 0x1.6376972bea4d0p-25; // 4.13813679705723846039e-08
|
private static final double P5 = 0x1.6376972bea4d0p-25; // 4.13813679705723846039e-08
|
||||||
|
|
||||||
private Exp() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double compute(double x) {
|
public static double compute(double x) {
|
||||||
double y;
|
double y;
|
||||||
double hi = 0.0;
|
double hi = 0.0;
|
||||||
|
@ -1015,8 +1012,8 @@ class FdLibm {
|
||||||
}
|
}
|
||||||
x = hi - lo;
|
x = hi - lo;
|
||||||
} else if (hx < 0x3e300000) { /* when |x|<2**-28 */
|
} else if (hx < 0x3e300000) { /* when |x|<2**-28 */
|
||||||
if (huge + x > one)
|
if (huge + x > 1.0)
|
||||||
return one + x; /* trigger inexact */
|
return 1.0 + x; /* trigger inexact */
|
||||||
} else {
|
} else {
|
||||||
k = 0;
|
k = 0;
|
||||||
}
|
}
|
||||||
|
@ -1025,9 +1022,9 @@ class FdLibm {
|
||||||
t = x * x;
|
t = x * x;
|
||||||
c = x - t*(P1 + t*(P2 + t*(P3 + t*(P4 + t*P5))));
|
c = x - t*(P1 + t*(P2 + t*(P3 + t*(P4 + t*P5))));
|
||||||
if (k == 0)
|
if (k == 0)
|
||||||
return one - ((x*c)/(c - 2.0) - x);
|
return 1.0 - ((x*c)/(c - 2.0) - x);
|
||||||
else
|
else
|
||||||
y = one - ((lo - (x*c)/(2.0 - c)) - hi);
|
y = 1.0 - ((lo - (x*c)/(2.0 - c)) - hi);
|
||||||
|
|
||||||
if(k >= -1021) {
|
if(k >= -1021) {
|
||||||
y = __HI(y, __HI(y) + (k << 20)); /* add k to y's exponent */
|
y = __HI(y, __HI(y) + (k << 20)); /* add k to y's exponent */
|
||||||
|
@ -1626,4 +1623,215 @@ class FdLibm {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) := x*shuge (overflow)
|
||||||
|
*
|
||||||
|
* Special cases:
|
||||||
|
* sinh(x) is |x| if x is +INF, -INF, or NaN.
|
||||||
|
* only sinh(0)=0 is exact for finite x.
|
||||||
|
*/
|
||||||
|
static final class Sinh {
|
||||||
|
private Sinh() {throw new UnsupportedOperationException();}
|
||||||
|
|
||||||
|
private static final double shuge = 1.0e307;
|
||||||
|
|
||||||
|
static double compute(double x) {
|
||||||
|
double t, w, h;
|
||||||
|
int ix, jx;
|
||||||
|
/* unsigned */ int lx;
|
||||||
|
|
||||||
|
// High word of |x|
|
||||||
|
jx = __HI(x);
|
||||||
|
ix = jx & 0x7fff_ffff;
|
||||||
|
|
||||||
|
// x is INF or NaN
|
||||||
|
if (ix >= 0x7ff0_0000) {
|
||||||
|
return x + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = 0.5;
|
||||||
|
if (jx < 0) {
|
||||||
|
h = -h;
|
||||||
|
}
|
||||||
|
// |x| in [0,22], return sign(x)*0.5*(E+E/(E+1)))
|
||||||
|
if (ix < 0x4036_0000) { // |x| < 22
|
||||||
|
if (ix < 0x3e30_0000) // |x| < 2**-28
|
||||||
|
if (shuge + x > 1.0) { // sinh(tiny) = tiny with inexact
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
t = StrictMath.expm1(Math.abs(x));
|
||||||
|
if (ix < 0x3ff0_0000) {
|
||||||
|
return h*(2.0 * t - t*t/(t + 1.0));
|
||||||
|
}
|
||||||
|
return h*(t + t/(t + 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| in [22, log(maxdouble)] return 0.5*exp(|x|)
|
||||||
|
if (ix < 0x4086_2E42) {
|
||||||
|
return h*StrictMath.exp(Math.abs(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| in [log(maxdouble), overflowthresold]
|
||||||
|
lx = __LO(x);
|
||||||
|
if (ix < 0x4086_33CE ||
|
||||||
|
((ix == 0x4086_33ce) &&
|
||||||
|
(Long.compareUnsigned(lx, 0x8fb9_f87d) <= 0 ))) {
|
||||||
|
w = StrictMath.exp(0.5 * Math.abs(x));
|
||||||
|
t = h * w;
|
||||||
|
return t * w;
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| > overflowthresold, sinh(x) overflow
|
||||||
|
return x * shuge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method :
|
||||||
|
* mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
|
||||||
|
* 1. Replace x by |x| (cosh(x) = cosh(-x)).
|
||||||
|
* 2.
|
||||||
|
* [ exp(x) - 1 ]^2
|
||||||
|
* 0 <= x <= ln2/2 : cosh(x) := 1 + -------------------
|
||||||
|
* 2*exp(x)
|
||||||
|
*
|
||||||
|
* exp(x) + 1/exp(x)
|
||||||
|
* ln2/2 <= x <= 22 : cosh(x) := -------------------
|
||||||
|
* 2
|
||||||
|
* 22 <= x <= lnovft : cosh(x) := exp(x)/2
|
||||||
|
* lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2)
|
||||||
|
* ln2ovft < x : cosh(x) := huge*huge (overflow)
|
||||||
|
*
|
||||||
|
* Special cases:
|
||||||
|
* cosh(x) is |x| if x is +INF, -INF, or NaN.
|
||||||
|
* only cosh(0)=1 is exact for finite x.
|
||||||
|
*/
|
||||||
|
static final class Cosh {
|
||||||
|
private Cosh() {throw new UnsupportedOperationException();}
|
||||||
|
|
||||||
|
private static final double huge = 1.0e300;
|
||||||
|
|
||||||
|
static double compute(double x) {
|
||||||
|
double t, w;
|
||||||
|
int ix;
|
||||||
|
/*unsigned*/ int lx;
|
||||||
|
|
||||||
|
// High word of |x|
|
||||||
|
ix = __HI(x);
|
||||||
|
ix &= 0x7fff_ffff;
|
||||||
|
|
||||||
|
// x is INF or NaN
|
||||||
|
if (ix >= 0x7ff0_0000) {
|
||||||
|
return x*x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|))
|
||||||
|
if (ix < 0x3fd6_2e43) {
|
||||||
|
t = StrictMath.expm1(Math.abs(x));
|
||||||
|
w = 1.0 + t;
|
||||||
|
if (ix < 0x3c80_0000) { // cosh(tiny) = 1
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
return 1.0 + (t * t)/(w + w);
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| in [0.5*ln2, 22], return (exp(|x|) + 1/exp(|x|)/2
|
||||||
|
if (ix < 0x4036_0000) {
|
||||||
|
t = StrictMath.exp(Math.abs(x));
|
||||||
|
return 0.5*t + 0.5/t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| in [22, log(maxdouble)] return 0.5*exp(|x|)
|
||||||
|
if (ix < 0x4086_2E42) {
|
||||||
|
return 0.5*StrictMath.exp(Math.abs(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| in [log(maxdouble), overflowthresold]
|
||||||
|
lx = __LO(x);
|
||||||
|
if (ix<0x4086_33CE ||
|
||||||
|
((ix == 0x4086_33ce) &&
|
||||||
|
(Integer.compareUnsigned(lx, 0x8fb9_f87d) <= 0))) {
|
||||||
|
w = StrictMath.exp(0.5*Math.abs(x));
|
||||||
|
t = 0.5*w;
|
||||||
|
return t*w;
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| > overflowthresold, cosh(x) overflow
|
||||||
|
return huge*huge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Hyperbolic Tangent of x
|
||||||
|
*
|
||||||
|
* Method :
|
||||||
|
* x -x
|
||||||
|
* e - e
|
||||||
|
* 0. tanh(x) is defined to be -----------
|
||||||
|
* x -x
|
||||||
|
* e + e
|
||||||
|
* 1. reduce x to non-negative by tanh(-x) = -tanh(x).
|
||||||
|
* 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+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.
|
||||||
|
*
|
||||||
|
* Special cases:
|
||||||
|
* tanh(NaN) is NaN;
|
||||||
|
* only tanh(0)=0 is exact for finite argument.
|
||||||
|
*/
|
||||||
|
static final class Tanh {
|
||||||
|
private Tanh() {throw new UnsupportedOperationException();}
|
||||||
|
|
||||||
|
private static final double tiny = 1.0e-300;
|
||||||
|
|
||||||
|
static double compute(double x) {
|
||||||
|
double t, z;
|
||||||
|
int jx, ix;
|
||||||
|
|
||||||
|
// High word of |x|.
|
||||||
|
jx = __HI(x);
|
||||||
|
ix = jx & 0x7fff_ffff;
|
||||||
|
|
||||||
|
// x is INF or NaN
|
||||||
|
if (ix >= 0x7ff0_0000) {
|
||||||
|
if (jx >= 0) { // tanh(+-inf)=+-1
|
||||||
|
return 1.0/x + 1.0;
|
||||||
|
} else { // tanh(NaN) = NaN
|
||||||
|
return 1.0/x - 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| < 22
|
||||||
|
if (ix < 0x4036_0000) { // |x| < 22
|
||||||
|
if (ix<0x3c80_0000) // |x| < 2**-55
|
||||||
|
return x*(1.0 + x); // tanh(small) = small
|
||||||
|
if (ix>=0x3ff0_0000) { // |x| >= 1
|
||||||
|
t = StrictMath.expm1(2.0*Math.abs(x));
|
||||||
|
z = 1.0 - 2.0/(t + 2.0);
|
||||||
|
} else {
|
||||||
|
t = StrictMath.expm1(-2.0*Math.abs(x));
|
||||||
|
z= -t/(t + 2.0);
|
||||||
|
}
|
||||||
|
} else { // |x| > 22, return +-1
|
||||||
|
z = 1.0 - tiny; // raised inexact flag
|
||||||
|
}
|
||||||
|
return (jx >= 0)? z: -z;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2081,7 +2081,9 @@ public final class StrictMath {
|
||||||
* @return The hyperbolic sine of {@code x}.
|
* @return The hyperbolic sine of {@code x}.
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static native double sinh(double x);
|
public static double sinh(double x) {
|
||||||
|
return FdLibm.Sinh.compute(x);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hyperbolic cosine of a {@code double} value.
|
* Returns the hyperbolic cosine of a {@code double} value.
|
||||||
|
@ -2105,7 +2107,9 @@ public final class StrictMath {
|
||||||
* @return The hyperbolic cosine of {@code x}.
|
* @return The hyperbolic cosine of {@code x}.
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static native double cosh(double x);
|
public static double cosh(double x) {
|
||||||
|
return FdLibm.Cosh.compute(x);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hyperbolic tangent of a {@code double} value.
|
* Returns the hyperbolic tangent of a {@code double} value.
|
||||||
|
@ -2136,7 +2140,9 @@ public final class StrictMath {
|
||||||
* @return The hyperbolic tangent of {@code x}.
|
* @return The hyperbolic tangent of {@code x}.
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public static native double tanh(double x);
|
public static double tanh(double x) {
|
||||||
|
return FdLibm.Tanh.compute(x);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns sqrt(<i>x</i><sup>2</sup> +<i>y</i><sup>2</sup>)
|
* Returns sqrt(<i>x</i><sup>2</sup> +<i>y</i><sup>2</sup>)
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8301833 8302026
|
* @bug 8301833 8302026 8301444
|
||||||
* @build Tests
|
* @build Tests
|
||||||
* @build FdlibmTranslit
|
* @build FdlibmTranslit
|
||||||
* @build ExhaustingTests
|
* @build ExhaustingTests
|
||||||
|
@ -73,12 +73,12 @@ public class ExhaustingTests {
|
||||||
new UnaryTestCase("log10", FdlibmTranslit::log10, StrictMath::log10, DEFAULT_SHIFT),
|
new UnaryTestCase("log10", FdlibmTranslit::log10, StrictMath::log10, DEFAULT_SHIFT),
|
||||||
new UnaryTestCase("log1p", FdlibmTranslit::log1p, StrictMath::log1p, DEFAULT_SHIFT),
|
new UnaryTestCase("log1p", FdlibmTranslit::log1p, StrictMath::log1p, DEFAULT_SHIFT),
|
||||||
|
|
||||||
// new UnaryTestCase("exp", FdlibmTranslit::exp, StrictMath::exp, DEFAULT_SHIFT),
|
new UnaryTestCase("exp", FdlibmTranslit::exp, StrictMath::exp, DEFAULT_SHIFT),
|
||||||
new UnaryTestCase("expm1", FdlibmTranslit::expm1, StrictMath::expm1, DEFAULT_SHIFT),
|
new UnaryTestCase("expm1", FdlibmTranslit::expm1, StrictMath::expm1, DEFAULT_SHIFT),
|
||||||
|
|
||||||
// new UnaryTestCase("sinh", FdlibmTranslit::sinh, StrictMath::sinh, DEFAULT_SHIFT),
|
new UnaryTestCase("sinh", FdlibmTranslit::sinh, StrictMath::sinh, DEFAULT_SHIFT),
|
||||||
// new UnaryTestCase("cosh", FdlibmTranslit::cosh, StrictMath::cosh, DEFAULT_SHIFT),
|
new UnaryTestCase("cosh", FdlibmTranslit::cosh, StrictMath::cosh, DEFAULT_SHIFT),
|
||||||
// new UnaryTestCase("tanh", FdlibmTranslit::tanh, StrictMath::tanh, DEFAULT_SHIFT),
|
new UnaryTestCase("tanh", FdlibmTranslit::tanh, StrictMath::tanh, DEFAULT_SHIFT),
|
||||||
|
|
||||||
// new UnaryTestCase("sin", FdlibmTranslit::sin, StrictMath::sin, DEFAULT_SHIFT),
|
// new UnaryTestCase("sin", FdlibmTranslit::sin, StrictMath::sin, DEFAULT_SHIFT),
|
||||||
// new UnaryTestCase("cos", FdlibmTranslit::cos, StrictMath::cos, DEFAULT_SHIFT),
|
// new UnaryTestCase("cos", FdlibmTranslit::cos, StrictMath::cos, DEFAULT_SHIFT),
|
||||||
|
@ -122,7 +122,7 @@ public class ExhaustingTests {
|
||||||
*/
|
*/
|
||||||
private static long testBinaryMethods() {
|
private static long testBinaryMethods() {
|
||||||
long failures = 0;
|
long failures = 0;
|
||||||
// Note: pow does _not_ have translit a port
|
// Note: pow does _not_ have a transliteration port.
|
||||||
|
|
||||||
// Shift of 16 for a binary method gives comparable running
|
// Shift of 16 for a binary method gives comparable running
|
||||||
// time to exhaustive testing of a unary method (testing every
|
// time to exhaustive testing of a unary method (testing every
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -140,7 +140,7 @@ public class ExpTests {
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
double x = start;
|
double x = start;
|
||||||
for (int i = 0; i < count; i++, x += increment) {
|
for (int i = 0; i < count; i++, x += increment) {
|
||||||
failures += testExpCase(x, FdlibmTranslit.Exp.compute(x));
|
failures += testExpCase(x, FdlibmTranslit.exp(x));
|
||||||
}
|
}
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,10 +102,27 @@ public class FdlibmTranslit {
|
||||||
return Log1p.compute(x);
|
return Log1p.compute(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double exp(double x) {
|
||||||
|
return Exp.compute(x);
|
||||||
|
}
|
||||||
|
|
||||||
public static double expm1(double x) {
|
public static double expm1(double x) {
|
||||||
return Expm1.compute(x);
|
return Expm1.compute(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double sinh(double x) {
|
||||||
|
return Sinh.compute(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double cosh(double x) {
|
||||||
|
return Cosh.compute(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double tanh(double x) {
|
||||||
|
return Tanh.compute(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns the arcsine of x.
|
/** Returns the arcsine of x.
|
||||||
*
|
*
|
||||||
* Method :
|
* Method :
|
||||||
|
@ -620,7 +637,7 @@ public class FdlibmTranslit {
|
||||||
* compiler will convert from decimal to binary accurately enough
|
* compiler will convert from decimal to binary accurately enough
|
||||||
* to produce the hexadecimal values shown.
|
* to produce the hexadecimal values shown.
|
||||||
*/
|
*/
|
||||||
static class Exp {
|
private static final class Exp {
|
||||||
private static final double one = 1.0;
|
private static final double one = 1.0;
|
||||||
private static final double[] halF = {0.5,-0.5,};
|
private static final double[] halF = {0.5,-0.5,};
|
||||||
private static final double huge = 1.0e+300;
|
private static final double huge = 1.0e+300;
|
||||||
|
@ -638,7 +655,7 @@ public class FdlibmTranslit {
|
||||||
private static final double P4 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */
|
private static final double P4 = -1.65339022054652515390e-06; /* 0xBEBBBD41, 0xC5D26BF1 */
|
||||||
private static final double P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
|
private static final double P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
|
||||||
|
|
||||||
public static double compute(double x) {
|
static double compute(double x) {
|
||||||
double y,hi=0,lo=0,c,t;
|
double y,hi=0,lo=0,c,t;
|
||||||
int k=0,xsb;
|
int k=0,xsb;
|
||||||
/*unsigned*/ int hx;
|
/*unsigned*/ int hx;
|
||||||
|
@ -1216,4 +1233,198 @@ public class FdlibmTranslit {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) := x*shuge (overflow)
|
||||||
|
*
|
||||||
|
* Special cases:
|
||||||
|
* sinh(x) is |x| if x is +INF, -INF, or NaN.
|
||||||
|
* only sinh(0)=0 is exact for finite x.
|
||||||
|
*/
|
||||||
|
private static final class Sinh {
|
||||||
|
private static final double one = 1.0, shuge = 1.0e307;
|
||||||
|
|
||||||
|
static double compute(double x) {
|
||||||
|
double t,w,h;
|
||||||
|
int ix,jx;
|
||||||
|
/* unsigned */ int lx;
|
||||||
|
|
||||||
|
/* High word of |x|. */
|
||||||
|
jx = __HI(x);
|
||||||
|
ix = jx&0x7fffffff;
|
||||||
|
|
||||||
|
/* x is INF or NaN */
|
||||||
|
if(ix>=0x7ff00000) return x+x;
|
||||||
|
|
||||||
|
h = 0.5;
|
||||||
|
if (jx<0) h = -h;
|
||||||
|
/* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
|
||||||
|
if (ix < 0x40360000) { /* |x|<22 */
|
||||||
|
if (ix<0x3e300000) /* |x|<2**-28 */
|
||||||
|
if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
|
||||||
|
t = FdlibmTranslit.expm1(Math.abs(x));
|
||||||
|
if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
|
||||||
|
return h*(t+t/(t+one));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
|
||||||
|
if (ix < 0x40862E42) return h*FdlibmTranslit.exp(Math.abs(x));
|
||||||
|
|
||||||
|
/* |x| in [log(maxdouble), overflowthresold] */
|
||||||
|
// Note: the original FDLIBM sources use
|
||||||
|
// lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
|
||||||
|
// to set lx to the low-order 32 bits of x. The expression
|
||||||
|
// in question is an alternate way to implement the
|
||||||
|
// functionality of the C FDLIBM __LO macro and the
|
||||||
|
// expression is coded to work on both big-edian and
|
||||||
|
// little-endian machines. However, this port will instead
|
||||||
|
// use the __LO method call to represent this
|
||||||
|
// functionality.
|
||||||
|
lx = __LO(x);
|
||||||
|
if (ix<0x408633CE || ((ix==0x408633ce)&&(Long.compareUnsigned(lx, 0x8fb9f87d) <= 0 ))) {
|
||||||
|
w = exp(0.5*Math.abs(x));
|
||||||
|
t = h*w;
|
||||||
|
return t*w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* |x| > overflowthresold, sinh(x) overflow */
|
||||||
|
return x*shuge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method :
|
||||||
|
* mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
|
||||||
|
* 1. Replace x by |x| (cosh(x) = cosh(-x)).
|
||||||
|
* 2.
|
||||||
|
* [ exp(x) - 1 ]^2
|
||||||
|
* 0 <= x <= ln2/2 : cosh(x) := 1 + -------------------
|
||||||
|
* 2*exp(x)
|
||||||
|
*
|
||||||
|
* exp(x) + 1/exp(x)
|
||||||
|
* ln2/2 <= x <= 22 : cosh(x) := -------------------
|
||||||
|
* 2
|
||||||
|
* 22 <= x <= lnovft : cosh(x) := exp(x)/2
|
||||||
|
* lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2)
|
||||||
|
* ln2ovft < x : cosh(x) := huge*huge (overflow)
|
||||||
|
*
|
||||||
|
* Special cases:
|
||||||
|
* cosh(x) is |x| if x is +INF, -INF, or NaN.
|
||||||
|
* only cosh(0)=1 is exact for finite x.
|
||||||
|
*/
|
||||||
|
private static final class Cosh {
|
||||||
|
private static final double one = 1.0, half=0.5, huge = 1.0e300;
|
||||||
|
static double compute(double x) {
|
||||||
|
double t,w;
|
||||||
|
int ix;
|
||||||
|
/*unsigned*/ int lx;
|
||||||
|
|
||||||
|
/* High word of |x|. */
|
||||||
|
ix = __HI(x);
|
||||||
|
ix &= 0x7fffffff;
|
||||||
|
|
||||||
|
/* x is INF or NaN */
|
||||||
|
if(ix>=0x7ff00000) return x*x;
|
||||||
|
|
||||||
|
/* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
|
||||||
|
if(ix<0x3fd62e43) {
|
||||||
|
t = expm1(Math.abs(x));
|
||||||
|
w = one+t;
|
||||||
|
if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */
|
||||||
|
return one+(t*t)/(w+w);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
|
||||||
|
if (ix < 0x40360000) {
|
||||||
|
t = exp(Math.abs(x));
|
||||||
|
return half*t+half/t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* |x| in [22, log(maxdouble)] return half*exp(|x|) */
|
||||||
|
if (ix < 0x40862E42) return half*exp(Math.abs(x));
|
||||||
|
|
||||||
|
/* |x| in [log(maxdouble), overflowthresold] */
|
||||||
|
// See note above in the sinh implementation for how this
|
||||||
|
// transliteration port uses __LO(x) in the line below
|
||||||
|
// that differs from the idiom used in the original FDLIBM.
|
||||||
|
lx = __LO(x);
|
||||||
|
if (ix<0x408633CE ||
|
||||||
|
((ix==0x408633ce)&&(Integer.compareUnsigned(lx, 0x8fb9f87d) <= 0))) {
|
||||||
|
w = exp(half*Math.abs(x));
|
||||||
|
t = half*w;
|
||||||
|
return t*w;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* |x| > overflowthresold, cosh(x) overflow */
|
||||||
|
return huge*huge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Hyperbolic Tangent of x
|
||||||
|
*
|
||||||
|
* Method :
|
||||||
|
* x -x
|
||||||
|
* e - e
|
||||||
|
* 0. tanh(x) is defined to be -----------
|
||||||
|
* x -x
|
||||||
|
* e + e
|
||||||
|
* 1. reduce x to non-negative by tanh(-x) = -tanh(x).
|
||||||
|
* 2. 0 <= x <= 2**-55 : tanh(x) := x*(one+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.
|
||||||
|
*
|
||||||
|
* Special cases:
|
||||||
|
* tanh(NaN) is NaN;
|
||||||
|
* only tanh(0)=0 is exact for finite argument.
|
||||||
|
*/
|
||||||
|
private static final class Tanh {
|
||||||
|
private static final double one=1.0, two=2.0, tiny = 1.0e-300;
|
||||||
|
static double compute(double x) {
|
||||||
|
double t,z;
|
||||||
|
int jx,ix;
|
||||||
|
|
||||||
|
/* High word of |x|. */
|
||||||
|
jx = __HI(x);
|
||||||
|
ix = jx&0x7fffffff;
|
||||||
|
|
||||||
|
/* x is INF or NaN */
|
||||||
|
if(ix>=0x7ff00000) {
|
||||||
|
if (jx>=0) return one/x+one; /* tanh(+-inf)=+-1 */
|
||||||
|
else return one/x-one; /* tanh(NaN) = NaN */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* |x| < 22 */
|
||||||
|
if (ix < 0x40360000) { /* |x|<22 */
|
||||||
|
if (ix<0x3c800000) /* |x|<2**-55 */
|
||||||
|
return x*(one+x); /* tanh(small) = small */
|
||||||
|
if (ix>=0x3ff00000) { /* |x|>=1 */
|
||||||
|
t = expm1(two*Math.abs(x));
|
||||||
|
z = one - two/(t+two);
|
||||||
|
} else {
|
||||||
|
t = expm1(-two*Math.abs(x));
|
||||||
|
z= -t/(t+two);
|
||||||
|
}
|
||||||
|
/* |x| > 22, return +-1 */
|
||||||
|
} else {
|
||||||
|
z = one - tiny; /* raised inexact flag */
|
||||||
|
}
|
||||||
|
return (jx>=0)? z: -z;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -20,17 +20,27 @@
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
import jdk.test.lib.RandomFactory;
|
||||||
|
import java.util.function.DoubleUnaryOperator;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 4851625
|
* @bug 4851625 8301444
|
||||||
|
* @key randomness
|
||||||
|
* @library /test/lib
|
||||||
|
* @build jdk.test.lib.RandomFactory
|
||||||
|
* @build Tests
|
||||||
|
* @build FdlibmTranslit
|
||||||
|
* @build HyperbolicTests
|
||||||
|
* @run main HyperbolicTests
|
||||||
* @summary Tests for StrictMath.{sinh, cosh, tanh}
|
* @summary Tests for StrictMath.{sinh, cosh, tanh}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tests in ../Math/HyperbolicTests.java test properties that
|
* The tests in ../Math/HyperbolicTests.java test properties that
|
||||||
* should hold for any implementation of the hyperbolic functions
|
* should hold for any implementation of the hyperbolic functions
|
||||||
* sinh, cos, and tanh, including the FDLIBM-based ones required by
|
* sinh, cosh, and tanh, including the FDLIBM-based ones required by
|
||||||
* the StrictMath class. Therefore, the test cases in
|
* the StrictMath class. Therefore, the test cases in
|
||||||
* ../Math/HyperbolicTests.java are run against both the Math and
|
* ../Math/HyperbolicTests.java are run against both the Math and
|
||||||
* StrictMath versions of the hyperbolic methods. The role of this
|
* StrictMath versions of the hyperbolic methods. The role of this
|
||||||
|
@ -42,22 +52,208 @@
|
||||||
public class HyperbolicTests {
|
public class HyperbolicTests {
|
||||||
private HyperbolicTests(){}
|
private HyperbolicTests(){}
|
||||||
|
|
||||||
static int testSinhCase(double input, double expected) {
|
public static void main(String... args) {
|
||||||
|
int failures = 0;
|
||||||
|
|
||||||
|
failures += testAgainstTranslitCommon();
|
||||||
|
|
||||||
|
failures += testAgainstTranslitSinh();
|
||||||
|
failures += testAgainstTranslitCosh();
|
||||||
|
failures += testAgainstTranslitTanh();
|
||||||
|
|
||||||
|
failures += testSinh();
|
||||||
|
failures += testCosh();
|
||||||
|
failures += testTanh();
|
||||||
|
|
||||||
|
if (failures > 0) {
|
||||||
|
System.err.println("Testing the hyperbolics incurred "
|
||||||
|
+ failures + " failures.");
|
||||||
|
throw new RuntimeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundle together groups of testing methods.
|
||||||
|
*/
|
||||||
|
private static enum HyperbolicTest {
|
||||||
|
SINH(HyperbolicTests::testSinhCase, FdlibmTranslit::sinh),
|
||||||
|
COSH(HyperbolicTests::testCoshCase, FdlibmTranslit::cosh),
|
||||||
|
TANH(HyperbolicTests::testTanhCase, FdlibmTranslit::tanh);
|
||||||
|
|
||||||
|
private DoubleDoubleToInt testCase;
|
||||||
|
private DoubleUnaryOperator transliteration;
|
||||||
|
|
||||||
|
HyperbolicTest(DoubleDoubleToInt testCase, DoubleUnaryOperator transliteration) {
|
||||||
|
this.testCase = testCase;
|
||||||
|
this.transliteration = transliteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleDoubleToInt testCase() {return testCase;}
|
||||||
|
public DoubleUnaryOperator transliteration() {return transliteration;}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize shared random number generator
|
||||||
|
private static java.util.Random random = RandomFactory.getRandom();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test against shared points of interest.
|
||||||
|
*/
|
||||||
|
private static int testAgainstTranslitCommon() {
|
||||||
|
int failures = 0;
|
||||||
|
double[] pointsOfInterest = {
|
||||||
|
Double.MIN_NORMAL,
|
||||||
|
1.0,
|
||||||
|
Tests.createRandomDouble(random),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var testMethods : HyperbolicTest.values()) {
|
||||||
|
for (double testPoint : pointsOfInterest) {
|
||||||
|
failures += testRangeMidpoint(testPoint, Math.ulp(testPoint), 1000, testMethods);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test StrictMath.sinh against transliteration port of sinh.
|
||||||
|
*/
|
||||||
|
private static int testAgainstTranslitSinh() {
|
||||||
|
int failures = 0;
|
||||||
|
double x;
|
||||||
|
|
||||||
|
// Probe near decision points in the FDLIBM algorithm.
|
||||||
|
double[] decisionPoints = {
|
||||||
|
0.0,
|
||||||
|
|
||||||
|
22.0,
|
||||||
|
-22.0,
|
||||||
|
|
||||||
|
0x1.0p-28,
|
||||||
|
-0x1.0p-28,
|
||||||
|
|
||||||
|
// StrictMath.log(Double.MAX_VALUE) ~= 709.782712893384
|
||||||
|
0x1.62e42fefa39efp9,
|
||||||
|
-0x1.62e42fefa39efp9,
|
||||||
|
|
||||||
|
// Largest argument with finite sinh, 710.4758600739439
|
||||||
|
0x1.633ce8fb9f87dp9,
|
||||||
|
-0x1.633ce8fb9f87dp9,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (double testPoint : decisionPoints) {
|
||||||
|
failures += testRangeMidpoint(testPoint, Math.ulp(testPoint), 1000, HyperbolicTest.SINH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test StrictMath.cosh against transliteration port of cosh.
|
||||||
|
*/
|
||||||
|
private static int testAgainstTranslitCosh() {
|
||||||
|
int failures = 0;
|
||||||
|
double x;
|
||||||
|
|
||||||
|
// Probe near decision points in the FDLIBM algorithm.
|
||||||
|
double[] decisionPoints = {
|
||||||
|
0.0,
|
||||||
|
|
||||||
|
22.0,
|
||||||
|
-22.0,
|
||||||
|
|
||||||
|
// StrictMath.log(2)/2 ~= 0.34657359027997264
|
||||||
|
0x1.62e42fefa39efp-2,
|
||||||
|
-0x1.62e42fefa39efp-2,
|
||||||
|
|
||||||
|
0x1.0p-28,
|
||||||
|
-0x1.0p-28,
|
||||||
|
|
||||||
|
// StrictMath.log(Double.MAX_VALUE) ~= 709.782712893384
|
||||||
|
0x1.62e42fefa39efp9,
|
||||||
|
-0x1.62e42fefa39efp9,
|
||||||
|
|
||||||
|
// Largest argument with finite cosh, 710.4758600739439
|
||||||
|
0x1.633ce8fb9f87dp9,
|
||||||
|
-0x1.633ce8fb9f87dp9,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (double testPoint : decisionPoints) {
|
||||||
|
failures += testRangeMidpoint(testPoint, Math.ulp(testPoint), 1000, HyperbolicTest.COSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test StrictMath.tanh against transliteration port of tanh
|
||||||
|
*/
|
||||||
|
private static int testAgainstTranslitTanh() {
|
||||||
|
int failures = 0;
|
||||||
|
double x;
|
||||||
|
|
||||||
|
// Probe near decision points in the FDLIBM algorithm.
|
||||||
|
double[] decisionPoints = {
|
||||||
|
0.0,
|
||||||
|
|
||||||
|
0x1.0p-55,
|
||||||
|
-0x1.0p-55,
|
||||||
|
|
||||||
|
1.0,
|
||||||
|
-1.0,
|
||||||
|
|
||||||
|
22.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (double testPoint : decisionPoints) {
|
||||||
|
failures += testRangeMidpoint(testPoint, Math.ulp(testPoint), 1000, HyperbolicTest.COSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface DoubleDoubleToInt {
|
||||||
|
int apply(double x, double y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int testRange(double start, double increment, int count,
|
||||||
|
HyperbolicTest testMethods) {
|
||||||
|
int failures = 0;
|
||||||
|
double x = start;
|
||||||
|
for (int i = 0; i < count; i++, x += increment) {
|
||||||
|
failures +=
|
||||||
|
testMethods.testCase().apply(x, testMethods.transliteration().applyAsDouble(x));
|
||||||
|
}
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int testRangeMidpoint(double midpoint, double increment, int count,
|
||||||
|
HyperbolicTest testMethods) {
|
||||||
|
int failures = 0;
|
||||||
|
double x = midpoint - increment*(count / 2) ;
|
||||||
|
for (int i = 0; i < count; i++, x += increment) {
|
||||||
|
failures +=
|
||||||
|
testMethods.testCase().apply(x, testMethods.transliteration().applyAsDouble(x));
|
||||||
|
}
|
||||||
|
return failures;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int testSinhCase(double input, double expected) {
|
||||||
return Tests.test("StrictMath.sinh(double)", input,
|
return Tests.test("StrictMath.sinh(double)", input,
|
||||||
StrictMath::sinh, expected);
|
StrictMath::sinh, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int testCoshCase(double input, double expected) {
|
private static int testCoshCase(double input, double expected) {
|
||||||
return Tests.test("StrictMath.cosh(double)", input,
|
return Tests.test("StrictMath.cosh(double)", input,
|
||||||
StrictMath::cosh, expected);
|
StrictMath::cosh, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int testTanhCase(double input, double expected) {
|
private static int testTanhCase(double input, double expected) {
|
||||||
return Tests.test("StrictMath.tanh(double)", input,
|
return Tests.test("StrictMath.tanh(double)", input,
|
||||||
StrictMath::tanh, expected);
|
StrictMath::tanh, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int testSinh() {
|
private static int testSinh() {
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
double [][] testCases = {
|
double [][] testCases = {
|
||||||
{0x1.5798ee2308c3ap-27, 0x1.5798ee2308c3bp-27},
|
{0x1.5798ee2308c3ap-27, 0x1.5798ee2308c3bp-27},
|
||||||
|
@ -147,12 +343,12 @@ public class HyperbolicTests {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (double[] testCase: testCases)
|
for (double[] testCase: testCases)
|
||||||
failures+=testSinhCase(testCase[0], testCase[1]);
|
failures += testSinhCase(testCase[0], testCase[1]);
|
||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int testCosh() {
|
private static int testCosh() {
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
double [][] testCases = {
|
double [][] testCases = {
|
||||||
{0x1.fffffffffb49fp-8, 0x1.00020000aaaabp0},
|
{0x1.fffffffffb49fp-8, 0x1.00020000aaaabp0},
|
||||||
|
@ -188,12 +384,12 @@ public class HyperbolicTests {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (double[] testCase: testCases)
|
for (double[] testCase: testCases)
|
||||||
failures+=testCoshCase(testCase[0], testCase[1]);
|
failures += testCoshCase(testCase[0], testCase[1]);
|
||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int testTanh() {
|
private static int testTanh() {
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
double [][] testCases = {
|
double [][] testCases = {
|
||||||
{0x1.5798ee2308c36p-27, 0x1.5798ee2308c36p-27},
|
{0x1.5798ee2308c36p-27, 0x1.5798ee2308c36p-27},
|
||||||
|
@ -257,23 +453,8 @@ public class HyperbolicTests {
|
||||||
};
|
};
|
||||||
|
|
||||||
for (double[] testCase: testCases)
|
for (double[] testCase: testCases)
|
||||||
failures+=testTanhCase(testCase[0], testCase[1]);
|
failures += testTanhCase(testCase[0], testCase[1]);
|
||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main(String [] argv) {
|
|
||||||
int failures = 0;
|
|
||||||
|
|
||||||
failures += testSinh();
|
|
||||||
failures += testCosh();
|
|
||||||
failures += testTanh();
|
|
||||||
|
|
||||||
if (failures > 0) {
|
|
||||||
System.err.println("Testing the hyperbolics incurred "
|
|
||||||
+ failures + " failures.");
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue