NPTL is no longer an add-on!
[platform/upstream/glibc.git] / math / s_ctanhf.c
1 /* Complex hyperbole tangent for float.
2    Copyright (C) 1997-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <complex.h>
21 #include <fenv.h>
22 #include <math.h>
23 #include <math_private.h>
24 #include <float.h>
25
26 __complex__ float
27 __ctanhf (__complex__ float x)
28 {
29   __complex__ float res;
30
31   if (__glibc_unlikely (!isfinite (__real__ x) || !isfinite (__imag__ x)))
32     {
33       if (__isinf_nsf (__real__ x))
34         {
35           __real__ res = __copysignf (1.0, __real__ x);
36           __imag__ res = __copysignf (0.0, __imag__ x);
37         }
38       else if (__imag__ x == 0.0)
39         {
40           res = x;
41         }
42       else
43         {
44           __real__ res = __nanf ("");
45           __imag__ res = __nanf ("");
46
47           if (__isinf_nsf (__imag__ x))
48             feraiseexcept (FE_INVALID);
49         }
50     }
51   else
52     {
53       float sinix, cosix;
54       float den;
55       const int t = (int) ((FLT_MAX_EXP - 1) * M_LN2 / 2);
56
57       /* tanh(x+iy) = (sinh(2x) + i*sin(2y))/(cosh(2x) + cos(2y))
58          = (sinh(x)*cosh(x) + i*sin(y)*cos(y))/(sinh(x)^2 + cos(y)^2).  */
59
60       if (__glibc_likely (fpclassify(__imag__ x) != FP_SUBNORMAL))
61         {
62           __sincosf (__imag__ x, &sinix, &cosix);
63         }
64       else
65         {
66           sinix = __imag__ x;
67           cosix = 1.0f;
68         }
69
70       if (fabsf (__real__ x) > t)
71         {
72           /* Avoid intermediate overflow when the imaginary part of
73              the result may be subnormal.  Ignoring negligible terms,
74              the real part is +/- 1, the imaginary part is
75              sin(y)*cos(y)/sinh(x)^2 = 4*sin(y)*cos(y)/exp(2x).  */
76           float exp_2t = __ieee754_expf (2 * t);
77
78           __real__ res = __copysignf (1.0, __real__ x);
79           __imag__ res = 4 * sinix * cosix;
80           __real__ x = fabsf (__real__ x);
81           __real__ x -= t;
82           __imag__ res /= exp_2t;
83           if (__real__ x > t)
84             {
85               /* Underflow (original real part of x has absolute value
86                  > 2t).  */
87               __imag__ res /= exp_2t;
88             }
89           else
90             __imag__ res /= __ieee754_expf (2 * __real__ x);
91         }
92       else
93         {
94           float sinhrx, coshrx;
95           if (fabsf (__real__ x) > FLT_MIN)
96             {
97               sinhrx = __ieee754_sinhf (__real__ x);
98               coshrx = __ieee754_coshf (__real__ x);
99             }
100           else
101             {
102               sinhrx = __real__ x;
103               coshrx = 1.0f;
104             }
105
106           if (fabsf (sinhrx) > fabsf (cosix) * FLT_EPSILON)
107             den = sinhrx * sinhrx + cosix * cosix;
108           else
109             den = cosix * cosix;
110           __real__ res = sinhrx * coshrx / den;
111           __imag__ res = sinix * cosix / den;
112         }
113     }
114
115   return res;
116 }
117 #ifndef __ctanhf
118 weak_alias (__ctanhf, ctanhf)
119 #endif