RFR: JDK-8301444: Port fdlibm hyperbolic transcendental functions to Java
Joe Darcy
darcy at openjdk.org
Sun Feb 5 03:11:27 UTC 2023
Initial pass of porting FDLIBM sinh/cosh/tanh to Java. I do intend to refactor the regression tests a bit to reduce duplication, but the actual ports should be ready for review.
Diff'ing the ports as before, original vs transliteration port:
$ diff -w Hyperbolic.c Hyperbolic.translit.java
1c1
< /* __ieee754_sinh(x)
---
> /**
17a18,19
> static class Sinh {
> private static final double one = 1.0, shuge = 1.0e307;
19,33c21
< #include "fdlibm.h"
<
< #ifdef __STDC__
< static const double one = 1.0, shuge = 1.0e307;
< #else
< static double one = 1.0, shuge = 1.0e307;
< #endif
<
< #ifdef __STDC__
< double __ieee754_sinh(double x)
< #else
< double __ieee754_sinh(x)
< double x;
< #endif
< {
---
> private static double compute(double x) {
36c24
< unsigned lx;
---
> /* unsigned */ int lx;
51c39
< t = expm1(fabs(x));
---
> t = FdlibmTranslit.expm1(Math.abs(x));
57c45
< if (ix < 0x40862E42) return h*__ieee754_exp(fabs(x));
---
> if (ix < 0x40862E42) return h*StrictMath.exp(Math.abs(x)); // TODO switch to translit
60,62c48,52
< lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
< if (ix<0x408633CE || ((ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d))) {
< w = __ieee754_exp(0.5*fabs(x));
---
> // lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
> // lx = (((*(unsigned*)&one)>>29)) + (unsigned*)&x ;
> lx = __LO(x);
> if (ix<0x408633CE || ((ix==0x408633ce)&&(Long.compareUnsigned(lx, 0x8fb9f87d) <= 0 ))) {
> w = StrictMath.exp(0.5*Math.abs(x)); // TODO switch to translit
70c60,62
< /* __ieee754_cosh(x)
---
> }
>
> /**
90,105c82,84
<
< #include "fdlibm.h"
<
< #ifdef __STDC__
< static const double one = 1.0, half=0.5, huge = 1.0e300;
< #else
< static double one = 1.0, half=0.5, huge = 1.0e300;
< #endif
<
< #ifdef __STDC__
< double __ieee754_cosh(double x)
< #else
< double __ieee754_cosh(x)
< double x;
< #endif
< {
---
> static class Cosh {
> private static final double one = 1.0, half=0.5, huge = 1.0e300;
> private static double compute(double x) {
108c87
< unsigned lx;
---
> /*unsigned*/ int lx;
119c98
< t = expm1(fabs(x));
---
> t = expm1(Math.abs(x));
127c106
< t = __ieee754_exp(fabs(x));
---
> t = StrictMath.exp(Math.abs(x)); // TODO switch to translit
132c111
< if (ix < 0x40862E42) return half*__ieee754_exp(fabs(x));
---
> if (ix < 0x40862E42) return half*StrictMath.exp(Math.abs(x)); // TODO switch to translit
135c114
< lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
---
> lx = __LO(x);
137,138c116,117
< ((ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d))) {
< w = __ieee754_exp(half*fabs(x));
---
> ((ix==0x408633ce)&&(Integer.compareUnsigned(lx, 0x8fb9f87d) <= 0))) {
> w = StrictMath.exp(half*Math.abs(x)); // TODO switch to translit
146c125,127
< /* Tanh(x)
---
> }
>
> /**
169,184c150,152
<
< #include "fdlibm.h"
<
< #ifdef __STDC__
< static const double one=1.0, two=2.0, tiny = 1.0e-300;
< #else
< static double one=1.0, two=2.0, tiny = 1.0e-300;
< #endif
<
< #ifdef __STDC__
< double tanh(double x)
< #else
< double tanh(x)
< double x;
< #endif
< {
---
> static class Tanh {
> private static final double one=1.0, two=2.0, tiny = 1.0e-300;
> static double compute(double x) {
203c171
< t = expm1(two*fabs(x));
---
> t = expm1(two*Math.abs(x));
206c174
< t = expm1(-two*fabs(x));
---
> t = expm1(-two*Math.abs(x));
214a183
> }
Note that the original has a in-line version of the "__LO" macro rather than using the macro.
And transliteration vs more idiomatic:
$ diff -w Hyperbolic.translit.java Hyperbolic.fdlibm.java
21c21
< private static double compute(double x) {
---
> static double compute(double x) {
26c26
< /* High word of |x|. */
---
> // High word of |x|
28c28
< ix = jx&0x7fffffff;
---
> ix = jx & 0x7fff_ffff;
30,31c30,33
< /* x is INF or NaN */
< if(ix>=0x7ff00000) return x+x;
---
> // x is INF or NaN
> if ( ix >= 0x7ff0_0000) {
> return x + x;
> }
34,40c36,48
< 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));
---
> 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 > one) { // 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 + one));
> }
44,45c52,55
< /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
< if (ix < 0x40862E42) return h*StrictMath.exp(Math.abs(x)); // TODO switch to translit
---
> // |x| in [22, log(maxdouble)] return 0.5*exp(|x|)
> if (ix < 0x4086_2E42) {
> return h*StrictMath.exp(Math.abs(x));
> }
47,49c57
< /* |x| in [log(maxdouble), overflowthresold] */
< // lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
< // lx = (((*(unsigned*)&one)>>29)) + (unsigned*)&x ;
---
> // |x| in [log(maxdouble), overflowthresold]
51,52c59,62
< if (ix<0x408633CE || ((ix==0x408633ce)&&(Long.compareUnsigned(lx, 0x8fb9f87d) <= 0 ))) {
< w = StrictMath.exp(0.5*Math.abs(x)); // TODO switch to translit
---
> if (ix < 0x4086_33CE ||
> ((ix == 0x4086_33ce) &&
> (Long.compareUnsigned(lx, 0x8fb9_f87d) <= 0 ))) {
> w = StrictMath.exp(0.5 * Math.abs(x));
57c67
< /* |x| > overflowthresold, sinh(x) overflow */
---
> // |x| > overflowthresold, sinh(x) overflow
84c94
< private static double compute(double x) {
---
> static double compute(double x) {
89c99
< /* High word of |x|. */
---
> // High word of |x|
91c101
< ix &= 0x7fffffff;
---
> ix &= 0x7fff_ffff;
93,94c103,106
< /* x is INF or NaN */
< if(ix>=0x7ff00000) return x*x;
---
> // x is INF or NaN
> if (ix >= 0x7ff_00000) {
> return x*x;
> }
96,98c108,110
< /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
< if(ix<0x3fd62e43) {
< t = expm1(Math.abs(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));
100c112,114
< if (ix<0x3c800000) return w; /* cosh(tiny) = 1 */
---
> if (ix < 0x3c80_0000) { // cosh(tiny) = 1
> return w;
> }
104,106c118,120
< /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
< if (ix < 0x40360000) {
< t = StrictMath.exp(Math.abs(x)); // TODO switch to translit
---
> // |x| in [0.5*ln2, 22], return (exp(|x|) + 1/exp(|x|)/2
> if (ix < 0x4036_0000) {
> t = StrictMath.exp(Math.abs(x));
110,111c124,127
< /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
< if (ix < 0x40862E42) return half*StrictMath.exp(Math.abs(x)); // TODO switch to translit
---
> // |x| in [22, log(maxdouble)] return half*exp(|x|)
> if (ix < 0x4086_2E42) {
> return half*StrictMath.exp(Math.abs(x));
> }
113c129
< /* |x| in [log(maxdouble), overflowthresold] */
---
> // |x| in [log(maxdouble), overflowthresold]
115,117c131,134
< if (ix<0x408633CE ||
< ((ix==0x408633ce)&&(Integer.compareUnsigned(lx, 0x8fb9f87d) <= 0))) {
< w = StrictMath.exp(half*Math.abs(x)); // TODO switch to translit
---
> if (ix<0x4086_33CE ||
> ((ix == 0x4086_33ce) &&
> (Integer.compareUnsigned(lx, 0x8fb9_f87d) <= 0))) {
> w = StrictMath.exp(half*Math.abs(x));
122c139
< /* |x| > overflowthresold, cosh(x) overflow */
---
> // |x| > overflowthresold, cosh(x) overflow
126d142
<
156c172
< /* High word of |x|. */
---
> // High word of |x|.
158c174
< ix = jx&0x7fffffff;
---
> ix = jx & 0x7fff_ffff;
160,163c176,182
< /* 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 is INF or NaN
> if (ix >= 0x7ff0_0000) {
> if (jx >= 0) { // tanh(+-inf)=+-1
> return one/x + one;
> } else { // tanh(NaN) = NaN
> return one/x - one;
> }
166,171c185,190
< /* |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));
---
> // |x| < 22
> if (ix < 0x4036_0000) { // |x| < 22
> if (ix<0x3c80_0000) // |x| < 2**-55
> return x*(one + x); // tanh(small) = small
> if (ix>=0x3ff0_0000) { // |x| >= 1
> t = StrictMath.expm1(two*Math.abs(x));
174c193
< t = expm1(-two*Math.abs(x));
---
> t = StrictMath.expm1(-two*Math.abs(x));
177,179c196,197
< /* |x| > 22, return +-1 */
< } else {
< z = one - tiny; /* raised inexact flag */
---
> } else { // |x| > 22, return +-1
> z = one - tiny; // raised inexact flag
-------------
Commit messages:
- JDK-8301444: Port fdlibm hyperbolic transcendental functions to Java
Changes: https://git.openjdk.org/jdk/pull/12429/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=12429&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8301444
Stats: 670 lines in 4 files changed: 650 ins; 15 del; 5 mod
Patch: https://git.openjdk.org/jdk/pull/12429.diff
Fetch: git fetch https://git.openjdk.org/jdk pull/12429/head:pull/12429
PR: https://git.openjdk.org/jdk/pull/12429
More information about the core-libs-dev
mailing list