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