]>
Commit | Line | Data |
---|---|---|
f029f4be | 1 | /* Complex hyperbole tangent for __float128. |
1a41c323 | 2 | Copyright (C) 1997-2013 Free Software Foundation, Inc. |
f029f4be TB |
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 "quadmath-imp.h" | |
21 | ||
22 | #ifdef HAVE_FENV_H | |
23 | # include <fenv.h> | |
24 | #endif | |
25 | ||
26 | ||
27 | __complex128 | |
28 | ctanhq (__complex128 x) | |
29 | { | |
30 | __complex128 res; | |
31 | ||
32 | if (__builtin_expect (!finiteq (__real__ x) || !finiteq (__imag__ x), 0)) | |
33 | { | |
34 | if (__quadmath_isinf_nsq (__real__ x)) | |
35 | { | |
36 | __real__ res = copysignq (1.0Q, __real__ x); | |
37 | __imag__ res = copysignq (0.0Q, __imag__ x); | |
38 | } | |
39 | else if (__imag__ x == 0.0Q) | |
40 | { | |
41 | res = x; | |
42 | } | |
43 | else | |
44 | { | |
45 | __real__ res = nanq (""); | |
46 | __imag__ res = nanq (""); | |
47 | ||
48 | #ifdef HAVE_FENV_H | |
49 | if (__quadmath_isinf_nsq (__imag__ x)) | |
50 | feraiseexcept (FE_INVALID); | |
51 | #endif | |
52 | } | |
53 | } | |
54 | else | |
55 | { | |
56 | __float128 sinix, cosix; | |
57 | __float128 den; | |
58 | const int t = (int) ((FLT128_MAX_EXP - 1) * M_LN2q / 2); | |
59 | int icls = fpclassifyq (__imag__ x); | |
60 | ||
61 | /* tanh(x+iy) = (sinh(2x) + i*sin(2y))/(cosh(2x) + cos(2y)) | |
62 | = (sinh(x)*cosh(x) + i*sin(y)*cos(y))/(sinh(x)^2 + cos(y)^2). */ | |
63 | ||
64 | if (__builtin_expect (icls != QUADFP_SUBNORMAL, 1)) | |
65 | { | |
66 | sincosq (__imag__ x, &sinix, &cosix); | |
67 | } | |
68 | else | |
69 | { | |
70 | sinix = __imag__ x; | |
71 | cosix = 1.0Q; | |
72 | } | |
73 | ||
74 | if (fabsq (__real__ x) > t) | |
75 | { | |
76 | /* Avoid intermediate overflow when the imaginary part of | |
77 | the result may be subnormal. Ignoring negligible terms, | |
78 | the real part is +/- 1, the imaginary part is | |
79 | sin(y)*cos(y)/sinh(x)^2 = 4*sin(y)*cos(y)/exp(2x). */ | |
80 | __float128 exp_2t = expq (2 * t); | |
81 | ||
82 | __real__ res = copysignq (1.0, __real__ x); | |
83 | __imag__ res = 4 * sinix * cosix; | |
84 | __real__ x = fabsq (__real__ x); | |
85 | __real__ x -= t; | |
86 | __imag__ res /= exp_2t; | |
87 | if (__real__ x > t) | |
88 | { | |
89 | /* Underflow (original real part of x has absolute value | |
90 | > 2t). */ | |
91 | __imag__ res /= exp_2t; | |
92 | } | |
93 | else | |
94 | __imag__ res /= expq (2 * __real__ x); | |
95 | } | |
96 | else | |
97 | { | |
98 | __float128 sinhrx, coshrx; | |
99 | if (fabsq (__real__ x) > FLT128_MIN) | |
100 | { | |
101 | sinhrx = sinhq (__real__ x); | |
102 | coshrx = coshq (__real__ x); | |
103 | } | |
104 | else | |
105 | { | |
106 | sinhrx = __real__ x; | |
107 | coshrx = 1.0Q; | |
108 | } | |
109 | ||
110 | if (fabsq (sinhrx) > fabsq (cosix) * FLT128_EPSILON) | |
111 | den = sinhrx * sinhrx + cosix * cosix; | |
112 | else | |
113 | den = cosix * cosix; | |
114 | __real__ res = sinhrx * coshrx / den; | |
115 | __imag__ res = sinix * cosix / den; | |
116 | } | |
117 | } | |
118 | ||
119 | return res; | |
120 | } |