This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
tanhl patch
- To: libc-alpha at sources dot redhat dot com
- Subject: tanhl patch
- From: Stephen L Moshier <moshier at mediaone dot net>
- Date: Mon, 18 Jun 2001 20:47:57 -0400 (EDT)
- Reply-To: moshier at moshier dot ne dot mediaone dot net
For very small x, tanh(x) => x.
The long double version of the hyperbolic tangent copies some
code from the double precision version that does this for x < 2^-55.
The threshold value is ok, but the code is not. Instead of x, it returns
x * (1 + x). The purpose of multiplying by 1 + x is to set the inexact
flag, while 1 + x is supposed to be equal to 1. But in long double
that isn't equal to one, so the incorrect outcome is that tanh(x) != x.
An extremely small number called tiny is already defined, so a simple fix
is to return x * (1 + tiny) for this case.
Here is a test program:
/* 2^-56 */
long double x = 1.387778780781445675529539585113525390625e-17L;
long double tanhl (long double);
main()
{
long double y = tanhl (x);
if (y != x)
abort ();
exit (0);
}
* sysdeps/ieee754/ldbl-96/s_tanhl.c (__tanhl): Make sure
result equals argument when x < 2^-55.
*** sysdeps/ieee754/ldbl-96/s_tanhl.c Tue Jul 13 20:15:23 1999
--- ./s_tanhl.c Mon Jun 18 20:29:48 2001
*************** static long double one=1.0, two=2.0, tin
*** 78,84 ****
if ((ix|j0|j1) == 0)
return x; /* x == +- 0 */
if (ix<0x3fc8) /* |x|<2**-55 */
! return x*(one+x); /* tanh(small) = small */
if (ix>=0x3fff) { /* |x|>=1 */
t = __expm1l(two*fabsl(x));
z = one - two/(t+two);
--- 78,84 ----
if ((ix|j0|j1) == 0)
return x; /* x == +- 0 */
if (ix<0x3fc8) /* |x|<2**-55 */
! return x*(one+tiny); /* tanh(small) = small */
if (ix>=0x3fff) { /* |x|>=1 */
t = __expm1l(two*fabsl(x));
z = one - two/(t+two);