RFR: JDK-8301444: Port fdlibm hyperbolic transcendental functions to Java [v11]

Brian Burkhalter bpb at openjdk.org
Thu Feb 16 23:12:08 UTC 2023


On Wed, 15 Feb 2023 22:44:40 GMT, Joe Darcy <darcy at openjdk.org> wrote:

>> 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
>
> Joe Darcy has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 14 commits:
> 
>  - Merge branch 'master' into JDK-8301444
>  - Refactor regression test.
>  - Small refactorings in Fdlibm.java
>  - Remove unnecessary semicolons.
>  - Add exhausting test coverage.
>  - Merge branch 'master' into JDK-8301444
>  - Merge branch 'master' into JDK-8301444
>  - Improve exp usage.
>  - Add additional note.
>  - Respond to review feedback.
>  - ... and 4 more: https://git.openjdk.org/jdk/compare/3ba15608...3c4e1812

Approved.

-------------

Marked as reviewed by bpb (Reviewer).

PR: https://git.openjdk.org/jdk/pull/12429


More information about the core-libs-dev mailing list