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