Bug 160759 - tanh(X) gives wrong results with complex X
tanh(X) gives wrong results with complex X
Product: Fedora
Classification: Fedora
Component: glibc (Show other bugs)
i386 Linux
medium Severity high
: ---
: ---
Assigned To: Jakub Jelinek
Depends On:
  Show dependency treegraph
Reported: 2005-06-17 01:28 EDT by Dmitri A. Sergatskov
Modified: 2007-11-30 17:11 EST (History)
1 user (show)

See Also:
Fixed In Version: 2.3.90-2
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Last Closed: 2005-07-10 16:25:00 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---

Attachments (Terms of Use)

  None (edit)
Description Dmitri A. Sergatskov 2005-06-17 01:28:52 EDT
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.8) Gecko/20050524 Fedora/1.0.4-4 Firefox/1.0.4

Description of problem:
tanh(x) gives wrong answer if x(0,pi/2) (or similar). This is an example program:
[dima@localhost bug]$ cat testcoth.cc
#include <complex>
#include <iostream>
#include <cmath>

using namespace std;

        complex<double> x(0, 3.1415926535/2.0);
        complex<double> y(1,0);
        cout << "x = " << x << endl;
        cout << "sinh(x) = " << sinh(x) << endl;
        cout << "cosh(x) = " << cosh(x) << endl;
        cout << "sinh(x)/cosh(x) = " << sinh(x)/cosh(x) << endl;
        cout << "tanh(x) = " << tanh(x) << endl;
        cout << "cosh(x)/sin(x) = " << cosh(x)/sinh(x) << endl;
        cout << "1/tanh(x) = " << y/tanh(x) << endl;
        return 0;

Version-Release number of selected component (if applicable):
gcc version 4.0.0 20050519 (Red Hat 4.0.0-8)

How reproducible:

Steps to Reproduce:
1.compile test program
2.run it

Actual Results:  [dima@localhost bug]$ g++ testcoth.cc -o testcoth
[dima@localhost bug]$ ./testcoth
x = (0,1.5708)
sinh(x) = (0,1)
cosh(x) = (4.48966e-11,0)
sinh(x)/cosh(x) = (0,2.22734e+10)
tanh(x) = (nan,inf)
cosh(x)/sin(x) = (0,-4.48966e-11)
1/tanh(x) = (nan,nan)

Expected Results:  x = (0,1.5708)
sinh(x) = (0,1)
cosh(x) = (4.48966e-11,0)
sinh(x)/cosh(x) = (0,2.22734e+10)
tanh(x) = (0,2.22734e+10)
cosh(x)/sin(x) = (0,-4.48966e-11)
1/tanh(x) = (0,-4.48966e-11)

Additional info:
Comment 1 Jakub Jelinek 2005-06-17 04:15:22 EDT
It's the underlying ctanh implementation:
#include <complex.h>
#include <math.h>
#include <stdio.h>

int main (void)
  _Complex double c, d;
  __real__ c = 0;
  __imag__ c = 3.1415926535/2.0;
  printf ("x %g + %gi\n", __real__ c, __imag__ c);
  d = csinh (c);
  printf ("sinh %g + %gi\n", __real__ d, __imag__ d);
  d = ccosh (c);
  printf ("cosh %g + %gi\n", __real__ d, __imag__ d);
  d = csinh (c) / ccosh (c);
  printf ("sinh/cosh %g + %gi\n", __real__ d, __imag__ d);
  d = ctanh (c);
  printf ("tanh %g + %gi\n", __real__ d, __imag__ d);
  d = ccosh (c) / csinh (c);
  printf ("cosh/sinh %g + %gi\n", __real__ d, __imag__ d);
  d = 1.0/ctanh (c);
  printf ("1/tanh %g + %gi\n", __real__ d, __imag__ d);
  return 0;

x 0 + 1.5708i
sinh 0 + 1i
cosh 4.48966e-11 + 0i
sinh/cosh 0 + 2.22734e+10i
tanh nan + infi
cosh/sinh 0 + -4.48966e-11i
1/tanh nan + nani
Comment 2 Jakub Jelinek 2005-06-17 06:02:16 EDT
tanh(z) is (e^z-e^-z)/(e^z+e^-z)
and e^(i*pi/2) is i, e^(-i*pi/2) is -i, so 2i/0.
2i/0 is nan + nani I think, though am not 100% sure about that.
The fact that sinh/cosh gives different number is just a matter of imprecise
Comment 3 Dmitri A. Sergatskov 2005-06-17 10:28:39 EDT
2*i/0 is Inf (or i*Inf, if it matters) (0/2i is obviously 0). 
(One way of thinking about these is to write z = r*exp(i*w), where r is real
amplitude and w is real phase. This way say lim(x/y) == lim((r_x)/(r_y)).)

I noticed the bug while calculatin coth(i*x) as 1/tanh(i*x). 
coth(i*pi/2) must be zero.

Also the difference between (0 + -4.48966e-11i) and (nan + nani) is
more than machine precision.

The bottom line is: glibc in FC3 got it right and in FC4 does not.
Comment 4 Jakub Jelinek 2005-06-17 10:44:02 EDT
"glibc in FC3 got it right and in FC4 does not"
This is not true, FC4, FC3, RHEL4 and RHEL3 glibc's behave all the same.
Only GCC 3.4.x and earlier did not use c{sin,cos,tan}h in <complex>.
Comment 5 Dmitri A. Sergatskov 2005-06-17 11:21:19 EDT
Fair enough. The correct(ed) statement is that the test program gives right 
answers in FC3 and wrong answers in FC4 and that needs fixing.

Also, this is might be somewhat off-topic, but there is a FDLIBM math library
on netlib which as far as I can tell has GNU-compatible license (it is developed
at Sun). This library often used as a reference library for math functions.
Any reason GNU libm cannot use it?

Comment 6 Jakub Jelinek 2005-06-17 11:25:59 EDT
GNU libm is heavily based on fdlibm.  fdlibm does not have complex math stuff
in it though.
Comment 7 Ulrich Drepper 2005-07-07 19:31:45 EDT
I've added some code upstream which reduces the error.
Comment 8 Jakub Jelinek 2005-07-10 16:25:00 EDT
Changes are in glibc-2.3.90-2.

Note You need to log in before you can comment on or make changes to this bug.