Bug 160759

Summary: tanh(X) gives wrong results with complex X
Product: [Fedora] Fedora Reporter: Dmitri A. Sergatskov <dasergatskov>
Component: glibcAssignee: Jakub Jelinek <jakub>
Status: CLOSED RAWHIDE QA Contact:
Severity: high Docs Contact:
Priority: medium    
Version: 4CC: drepper
Target Milestone: ---   
Target Release: ---   
Hardware: i386   
OS: Linux   
Whiteboard:
Fixed In Version: 2.3.90-2 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2005-07-10 20:25:00 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Dmitri A. Sergatskov 2005-06-17 05:28:52 UTC
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;

main()
{
        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:
Always

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

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 08:15:22 UTC
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 10:02:16 UTC
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
calculations.

Comment 3 Dmitri A. Sergatskov 2005-06-17 14:28:39 UTC
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 14:44:02 UTC
"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 15:21:19 UTC
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?

Sincerely,
Dmitri.
 

Comment 6 Jakub Jelinek 2005-06-17 15:25:59 UTC
GNU libm is heavily based on fdlibm.  fdlibm does not have complex math stuff
in it though.

Comment 7 Ulrich Drepper 2005-07-07 23:31:45 UTC
I've added some code upstream which reduces the error.

Comment 8 Jakub Jelinek 2005-07-10 20:25:00 UTC
Changes are in glibc-2.3.90-2.