RFR: 8377223: Port fdlibm atanh to Java

Anton Artemov aartemov at openjdk.org
Wed Feb 18 11:32:22 UTC 2026


On Wed, 18 Feb 2026 10:10:31 GMT, Anton Artemov <aartemov at openjdk.org> wrote:

> Hi, please consider the following changes:
> 
> This is a port of FDLIBM atanh method.

Original C vs transliteration port:


$ diff -w fdlib_atanh.c Atanh.translit.java
1c1,3
< /* __ieee754_atanh(x)
---
> /**
>  *  Return the Inverse Hyperbolic Tangent of x
>  *
17a20,23
> private static final class Atanh {
>       private static final double zero = 0.0;
>       private static final double one = 1.0;
>       private static final double huge = 1.0e300;
19,35c25
< #include "fdlibm.h"
<
< #ifdef __STDC__
< static const double one = 1.0, huge = 1e300;
< #else
< static double one = 1.0, huge = 1e300;
< #endif
<
< static double zero = 0.0;
<
< #ifdef __STDC__
<       double __ieee754_atanh(double x)
< #else
<       double __ieee754_atanh(x)
<       double x;
< #endif
< {
---
>       static double compute(double x) {
38c28
<       unsigned lx;
---
>               /*unsigned*/ int lx;
47c37
<       __HI(x) = ix;           /* x <- |x| */
---
>               x = __HI(x, ix);     /* x <- |x| */
53a44
>       }



Transliteration vs more idiomatic port:

$ diff -w Atanh.translit.java Atanh.fdlibm.java
3d2
<  *
5,9d3
<  *    1.Reduced x to positive by atanh(-x) = -atanh(x)
<  *    2.For x>=0.5
<  *                1              2x                          x
<  *    atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
<  *                2             1 - x                      1 - x
11,12d4
<  *  For x<0.5
<  *   atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
14,17c6,12
<  *  Special cases:
<  *    atanh(x) is NaN if |x| > 1 with signal;
<  *    atanh(NaN) is that NaN with no signal;
<  *    atanh(+-1) is +-INF with signal.
---
>  *      atanh(x) is defined so that atanh(tanh(alpha)) = alpha, -∞ < alpha < ∞
>  *      and tanh(atanh(x)) = x, -1 &lt x &lt 1;
>  *      It can be written as atanh(x) = 0.5 * log1p(2 * x/(1-x)), -1 < x < 1;
>  *      1.
>  *          atanh(x) := 0.5 * log1p(2 * x/(1 - x)), if |x| >= 0.5,
>  *                   := 0.5 * log1p(2x + 2x * x/(1 - x)), if |x| < 0.5.
>  *
18a14,18
>  *
>  * Special cases:
>  *      only atanh(±0)=±0 is exact for finite x.
>  *      atanh(NaN) is NaN
>  *      atanh(±1) is ±∞
20c20
< private static final class Atanh {
---
> static final class Atanh {
31,32c31,32
<               ix = hx&0x7fffffff;
<               if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
---
>               ix = hx & 0x7fff_ffff;
>               if ((ix | ((lx | (-lx)) >> 31)) > 0x3ff0_0000) {     /* |x| > 1 */
34c34,35
<               if(ix==0x3ff00000)
---
>               }
>               if (ix == 0x3ff0_0000) {
36c37,40
<               if(ix<0x3e300000&&(huge+x)>zero) return x;  /* x<2**-28 */
---
>               }
>               if (ix < 0x3e30_0000 && (huge + x) > zero) {
>                       return x;                                        /* x<2**-28 */
>               }
38c42
<               if(ix<0x3fe00000) {     /* x < 0.5 */
---
>               if (ix < 0x3fe0_0000) {                              /* x < 0.5 */
40c44
<                       t = 0.5*log1p(t+t*x/(one-x));
---
>                       t = 0.5 * Log1p.compute(t + t*x/(one - x));
42,43c46,51
<                       t = 0.5*log1p((x+x)/(one-x));
<               if(hx>=0) return t; else return -t;
---
>                       t = 0.5 * Log1p.compute((x + x)/(one - x));
>               if (hx >= 0) {
>                       return t;
>               } else {
>                       return -t;
>               }

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

PR Comment: https://git.openjdk.org/jdk/pull/29782#issuecomment-3919911569


More information about the core-libs-dev mailing list