Red Hat Bugzilla – Bug 160759

tanh(X) gives wrong results with complex X

Last modified: 2007-11-30 17:11:08 EST

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:

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

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.

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.

"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>.

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.

GNU libm is heavily based on fdlibm. fdlibm does not have complex math stuff in it though.

I've added some code upstream which reduces the error.

Changes are in glibc-2.3.90-2.