OLD | NEW |
1 /* origin: FreeBSD /usr/src/lib/msun/src/s_ctanh.c */ | 1 /* origin: FreeBSD /usr/src/lib/msun/src/s_ctanh.c */ |
2 /*- | 2 /*- |
3 * Copyright (c) 2011 David Schultz | 3 * Copyright (c) 2011 David Schultz |
4 * All rights reserved. | 4 * All rights reserved. |
5 * | 5 * |
6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
8 * are met: | 8 * are met: |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice unmodified, this list of conditions, and the following | 10 * notice unmodified, this list of conditions, and the following |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 * | 58 * |
59 * Modifications: | 59 * Modifications: |
60 * | 60 * |
61 * I omitted the original algorithm's handling of overflow in tan(x) after | 61 * I omitted the original algorithm's handling of overflow in tan(x) after |
62 * verifying with nearpi.c that this can't happen in IEEE single or double | 62 * verifying with nearpi.c that this can't happen in IEEE single or double |
63 * precision. I also handle large x differently. | 63 * precision. I also handle large x differently. |
64 */ | 64 */ |
65 | 65 |
66 #include "libm.h" | 66 #include "libm.h" |
67 | 67 |
68 double complex ctanh(double complex z) | 68 double complex ctanh(double complex z) { |
69 { | 69 double x, y; |
70 » double x, y; | 70 double t, beta, s, rho, denom; |
71 » double t, beta, s, rho, denom; | 71 uint32_t hx, ix, lx; |
72 » uint32_t hx, ix, lx; | |
73 | 72 |
74 » x = creal(z); | 73 x = creal(z); |
75 » y = cimag(z); | 74 y = cimag(z); |
76 | 75 |
77 » EXTRACT_WORDS(hx, lx, x); | 76 EXTRACT_WORDS(hx, lx, x); |
78 » ix = hx & 0x7fffffff; | 77 ix = hx & 0x7fffffff; |
79 | 78 |
80 » /* | 79 /* |
81 » * ctanh(NaN + i 0) = NaN + i 0 | 80 * ctanh(NaN + i 0) = NaN + i 0 |
82 » * | 81 * |
83 » * ctanh(NaN + i y) = NaN + i NaN for y != 0 | 82 * ctanh(NaN + i y) = NaN + i NaN for y != 0 |
84 » * | 83 * |
85 » * The imaginary part has the sign of x*sin(2*y), but there's no | 84 * The imaginary part has the sign of x*sin(2*y), but there's no |
86 » * special effort to get this right. | 85 * special effort to get this right. |
87 » * | 86 * |
88 » * ctanh(+-Inf +- i Inf) = +-1 +- 0 | 87 * ctanh(+-Inf +- i Inf) = +-1 +- 0 |
89 » * | 88 * |
90 » * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite | 89 * ctanh(+-Inf + i y) = +-1 + 0 sin(2y) for y finite |
91 » * | 90 * |
92 » * The imaginary part of the sign is unspecified. This special | 91 * The imaginary part of the sign is unspecified. This special |
93 » * case is only needed to avoid a spurious invalid exception when | 92 * case is only needed to avoid a spurious invalid exception when |
94 » * y is infinite. | 93 * y is infinite. |
95 » */ | 94 */ |
96 » if (ix >= 0x7ff00000) { | 95 if (ix >= 0x7ff00000) { |
97 » » if ((ix & 0xfffff) | lx) /* x is NaN */ | 96 if ((ix & 0xfffff) | lx) /* x is NaN */ |
98 » » » return CMPLX(x, (y == 0 ? y : x * y)); | 97 return CMPLX(x, (y == 0 ? y : x * y)); |
99 » » SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */ | 98 SET_HIGH_WORD(x, hx - 0x40000000); /* x = copysign(1, x) */ |
100 » » return CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))); | 99 return CMPLX(x, copysign(0, isinf(y) ? y : sin(y) * cos(y))); |
101 » } | 100 } |
102 | 101 |
103 » /* | 102 /* |
104 » * ctanh(+-0 + i NAN) = +-0 + i NaN | 103 * ctanh(+-0 + i NAN) = +-0 + i NaN |
105 » * ctanh(+-0 +- i Inf) = +-0 + i NaN | 104 * ctanh(+-0 +- i Inf) = +-0 + i NaN |
106 » * ctanh(x + i NAN) = NaN + i NaN | 105 * ctanh(x + i NAN) = NaN + i NaN |
107 » * ctanh(x +- i Inf) = NaN + i NaN | 106 * ctanh(x +- i Inf) = NaN + i NaN |
108 » */ | 107 */ |
109 » if (!isfinite(y)) | 108 if (!isfinite(y)) |
110 » » return CMPLX(x ? y - y : x, y - y); | 109 return CMPLX(x ? y - y : x, y - y); |
111 | 110 |
112 » /* | 111 /* |
113 » * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the | 112 * ctanh(+-huge + i +-y) ~= +-1 +- i 2sin(2y)/exp(2x), using the |
114 » * approximation sinh^2(huge) ~= exp(2*huge) / 4. | 113 * approximation sinh^2(huge) ~= exp(2*huge) / 4. |
115 » * We use a modified formula to avoid spurious overflow. | 114 * We use a modified formula to avoid spurious overflow. |
116 » */ | 115 */ |
117 » if (ix >= 0x40360000) { /* x >= 22 */ | 116 if (ix >= 0x40360000) { /* x >= 22 */ |
118 » » double exp_mx = exp(-fabs(x)); | 117 double exp_mx = exp(-fabs(x)); |
119 » » return CMPLX(copysign(1, x), 4 * sin(y) * cos(y) * exp_mx * exp_
mx); | 118 return CMPLX(copysign(1, x), 4 * sin(y) * cos(y) * exp_mx * exp_mx); |
120 » } | 119 } |
121 | 120 |
122 » /* Kahan's algorithm */ | 121 /* Kahan's algorithm */ |
123 » t = tan(y); | 122 t = tan(y); |
124 » beta = 1.0 + t * t; /* = 1 / cos^2(y) */ | 123 beta = 1.0 + t * t; /* = 1 / cos^2(y) */ |
125 » s = sinh(x); | 124 s = sinh(x); |
126 » rho = sqrt(1 + s * s); /* = cosh(x) */ | 125 rho = sqrt(1 + s * s); /* = cosh(x) */ |
127 » denom = 1 + beta * s * s; | 126 denom = 1 + beta * s * s; |
128 » return CMPLX((beta * rho * s) / denom, t / denom); | 127 return CMPLX((beta * rho * s) / denom, t / denom); |
129 } | 128 } |
OLD | NEW |