From Bugzilla Helper: User-Agent: Mozilla/4.77 [en] (X11; U; Linux 2.4.2-2 i586) Description of problem: The hyperbolic tangent of a negative number is supposed to be negative. While the float and double versions of tanh return the correct result, the long double version tanhl always returns a positive number. How reproducible: Always Steps to Reproduce: Compile and run the following program: #include <stdio.h> #define __USE_ISOC99 1 #include <math.h> main () { if (tanh (-1) == (double) tanhl (-1)) { printf ("tanh (-1) = %+Lg\n", tanhl (-1)); return 0; } else { printf ("tanhl (-1) returns %+Lg; should be %+g\n", tanhl (-1), tanh (-1)); return 1; } } Actual Results: tanhl (-1) returns +0.761594; should be -0.761594 Expected Results: tanh (-1) = -0.761594 Additional info: This error stems from an incorrect implicit cast in the glibc code. Look carefully at the following files in glibc-2.2.3/sysdeps/ieee754/ldbl-96/: math_ldbl.h:15 int sign_exponent:16; math_ldbl.h:46 (exp) = ew_u.parts.sign_exponent; s_tanhl.c:62 int32_t se; s_tanhl.c:66 GET_LDOUBLE_WORDS(se,j0,j1,x); s_tanhl.c:93 return (se>0x7fff)? -z: z; Since sign_exponent is a 16-bit *signed* integer, it gets sign-extended when assigned to 'se' which is a 32-bit signed integer. The comparison at the end of tanhl() will always be false, since a 16-bit signed integer can never be greater than SHRT_MAX (0x7fff).
This has been fixed already, see: 2001-05-14 Stephen L Moshier <moshier> * sysdeps/ieee754/ldbl-96/s_tanhl.c (__tanhl): Fix sign test. @@ -90,6 +90,6 @@ static long double one=1.0, two=2.0, tin } else { z = one - tiny; /* raised inexact flag */ } - return (se>0x7fff)? -z: z; + return (se&0x8000)? -z: z; } weak_alias (__tanhl, tanhl)
Included in glibc-2.2.3-11.