Java / C: implementation of OpenJDK native tanh () wrong?

I searched for some of the Java Math source code sources. Especially tanh() , as I was curious to see how they implemented this one. However, what I found surprised me:

 double tanh(double x) { ... if (ix < 0x40360000) { /* |x|<22 */ if (ix<0x3c800000) /* |x|<2**-55 */ return x*(one+x); /* tanh(small) = small */ ... } 

As noted in the comment, the taylor tanh (x) series around 0 starts with:

 tanh(x) = x - x^3/3 + ... 

Then why does it look like they implemented it like:

 tanh(x) = x * (1 + x) = x + x^2 

This is clearly not a valid extension and even worse approximation than just using tanh(x) = x (which would be faster), as shown in this figure:

enter image description here

(The bold line is at the top. Another gray line is log(abs(x(1+x) - tanh(x))) . The sigmoid, of course, is tanh(x) .)

So, is it an implementation error, or is it a hack to fix some problem (for example, numerical problems that I really can't think of)? Note that I expect the result of both approaches to be exactly the same as if there werenโ€™t enough mantissa bits to actually add 1 + x for x <2 ^. (- 55)

EDIT: I will include a link to the version of the code at the time of writing for future reference, as this may be fixed.

+8
java c math floating-point ieee-754
source share
1 answer

Under the conditions in which this code runs, and assuming that IEEE-754 double-precision representations and double-point arithmetic are used, 1.0 + x will always be evaluated to 1.0 , so x * (1.0 + x) will always evaluate x . The only externally (for the function) observed effect of performing the calculation, as it is done instead of just returning x , is to set the โ€œinaccurateโ€ IEEE status flag.

Although I do not know how to request FP status flags from Java, other native code may request them. However, most likely, the practical reason for implementing these notes is given in Javadocs for java.StrictMath :

To ensure portability of Java programs, the definitions of some of the numerical functions in this package require that they produce the same results as some published algorithms. These algorithms are available from the well-known netlib network library as the Freely Distributed Math Library package, fdlibm. These algorithms, written in the C programming language, are then understood to be performed with all floating point operations, following the rules of Java floating point arithmetic.

The Java math library is defined with respect to fdlibm version 5.3. If fdlibm provides more than one definition for a function (for example, acos), use the IEEE 754 Primary Function version (found in a file whose name starts with the letter e). Methods that require fdlibm semantics are sin , cos , tan , asin , acos , atan , exp , log , log10 , cbrt , atan2 , pow , sinh , cosh , tanh , hypot , expm1 and log1p .

(Emphasis added.) You note in the source code C a #include "fdlibm.h" , which seems to bind it to Javadoc comments.

+6
source share

All Articles