RFR: JDK-8301444: Port fdlibm hyperbolic transcendental functions to Java
Andrey Turbanov
aturbanov at openjdk.org
Mon Feb 6 08:36:57 UTC 2023
On Sun, 5 Feb 2023 03:05:55 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
src/java.base/share/classes/java/lang/FdLibm.java line 1228:
> 1226:
> 1227: // x is INF or NaN
> 1228: if ( ix >= 0x7ff0_0000) {
Suggestion:
if (ix >= 0x7ff0_0000) {
src/java.base/share/classes/java/lang/FdLibm.java line 1233:
> 1231:
> 1232: h = 0.5;
> 1233: if ( jx < 0) {
Suggestion:
if (jx < 0) {
test/jdk/java/lang/StrictMath/HyperbolicTests.java line 86:
> 84:
> 85: // ... and just below subnormal threshold ...
> 86: x = Math.nextDown(Double.MIN_NORMAL);
Suggestion:
x = Math.nextDown(Double.MIN_NORMAL);
test/jdk/java/lang/StrictMath/HyperbolicTests.java line 140:
> 138:
> 139: // ... and just below subnormal threshold ...
> 140: x = Math.nextDown(Double.MIN_NORMAL);
Suggestion:
x = Math.nextDown(Double.MIN_NORMAL);
test/jdk/java/lang/StrictMath/HyperbolicTests.java line 198:
> 196:
> 197: // ... and just below subnormal threshold ...
> 198: x = Math.nextDown(Double.MIN_NORMAL);
Suggestion:
x = Math.nextDown(Double.MIN_NORMAL);
-------------
PR: https://git.openjdk.org/jdk/pull/12429
More information about the core-libs-dev
mailing list