williamr@4
|
1 |
// (C) Copyright John Maddock 2005.
|
williamr@4
|
2 |
// Use, modification and distribution are subject to the
|
williamr@4
|
3 |
// Boost Software License, Version 1.0. (See accompanying file
|
williamr@4
|
4 |
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
williamr@2
|
5 |
|
williamr@4
|
6 |
#ifndef BOOST_MATH_COMPLEX_ATANH_INCLUDED
|
williamr@4
|
7 |
#define BOOST_MATH_COMPLEX_ATANH_INCLUDED
|
williamr@2
|
8 |
|
williamr@4
|
9 |
#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
|
williamr@4
|
10 |
# include <boost/math/complex/details.hpp>
|
williamr@4
|
11 |
#endif
|
williamr@4
|
12 |
#ifndef BOOST_MATH_LOG1P_INCLUDED
|
williamr@4
|
13 |
# include <boost/math/special_functions/log1p.hpp>
|
williamr@4
|
14 |
#endif
|
williamr@4
|
15 |
#include <boost/assert.hpp>
|
williamr@2
|
16 |
|
williamr@4
|
17 |
#ifdef BOOST_NO_STDC_NAMESPACE
|
williamr@4
|
18 |
namespace std{ using ::sqrt; using ::fabs; using ::acos; using ::asin; using ::atan; using ::atan2; }
|
williamr@4
|
19 |
#endif
|
williamr@2
|
20 |
|
williamr@4
|
21 |
namespace boost{ namespace math{
|
williamr@2
|
22 |
|
williamr@4
|
23 |
template<class T>
|
williamr@4
|
24 |
std::complex<T> atanh(const std::complex<T>& z)
|
williamr@4
|
25 |
{
|
williamr@4
|
26 |
//
|
williamr@4
|
27 |
// References:
|
williamr@4
|
28 |
//
|
williamr@4
|
29 |
// Eric W. Weisstein. "Inverse Hyperbolic Tangent."
|
williamr@4
|
30 |
// From MathWorld--A Wolfram Web Resource.
|
williamr@4
|
31 |
// http://mathworld.wolfram.com/InverseHyperbolicTangent.html
|
williamr@4
|
32 |
//
|
williamr@4
|
33 |
// Also: The Wolfram Functions Site,
|
williamr@4
|
34 |
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/
|
williamr@4
|
35 |
//
|
williamr@4
|
36 |
// Also "Abramowitz and Stegun. Handbook of Mathematical Functions."
|
williamr@4
|
37 |
// at : http://jove.prohosting.com/~skripty/toc.htm
|
williamr@4
|
38 |
//
|
williamr@4
|
39 |
|
williamr@4
|
40 |
static const T half_pi = static_cast<T>(1.57079632679489661923132169163975144L);
|
williamr@4
|
41 |
static const T pi = static_cast<T>(3.141592653589793238462643383279502884197L);
|
williamr@4
|
42 |
static const T one = static_cast<T>(1.0L);
|
williamr@4
|
43 |
static const T two = static_cast<T>(2.0L);
|
williamr@4
|
44 |
static const T four = static_cast<T>(4.0L);
|
williamr@4
|
45 |
static const T zero = static_cast<T>(0);
|
williamr@4
|
46 |
static const T a_crossover = static_cast<T>(0.3L);
|
williamr@2
|
47 |
|
williamr@4
|
48 |
T x = std::fabs(z.real());
|
williamr@4
|
49 |
T y = std::fabs(z.imag());
|
williamr@2
|
50 |
|
williamr@4
|
51 |
T real, imag; // our results
|
williamr@2
|
52 |
|
williamr@4
|
53 |
T safe_upper = detail::safe_max(two);
|
williamr@4
|
54 |
T safe_lower = detail::safe_min(static_cast<T>(2));
|
williamr@2
|
55 |
|
williamr@4
|
56 |
//
|
williamr@4
|
57 |
// Begin by handling the special cases specified in C99:
|
williamr@4
|
58 |
//
|
williamr@4
|
59 |
if(detail::test_is_nan(x))
|
williamr@4
|
60 |
{
|
williamr@4
|
61 |
if(detail::test_is_nan(y))
|
williamr@4
|
62 |
return std::complex<T>(x, x);
|
williamr@4
|
63 |
else if(std::numeric_limits<T>::has_infinity && (y == std::numeric_limits<T>::infinity()))
|
williamr@4
|
64 |
return std::complex<T>(0, ((z.imag() < 0) ? -half_pi : half_pi));
|
williamr@4
|
65 |
else
|
williamr@4
|
66 |
return std::complex<T>(x, x);
|
williamr@4
|
67 |
}
|
williamr@4
|
68 |
else if(detail::test_is_nan(y))
|
williamr@4
|
69 |
{
|
williamr@4
|
70 |
if(x == 0)
|
williamr@4
|
71 |
return std::complex<T>(x, y);
|
williamr@4
|
72 |
if(std::numeric_limits<T>::has_infinity && (x == std::numeric_limits<T>::infinity()))
|
williamr@4
|
73 |
return std::complex<T>(0, y);
|
williamr@4
|
74 |
else
|
williamr@4
|
75 |
return std::complex<T>(y, y);
|
williamr@4
|
76 |
}
|
williamr@4
|
77 |
else if((x > safe_lower) && (x < safe_upper) && (y > safe_lower) && (y < safe_upper))
|
williamr@4
|
78 |
{
|
williamr@2
|
79 |
|
williamr@4
|
80 |
T xx = x*x;
|
williamr@4
|
81 |
T yy = y*y;
|
williamr@4
|
82 |
T x2 = x * two;
|
williamr@4
|
83 |
|
williamr@4
|
84 |
///
|
williamr@4
|
85 |
// The real part is given by:
|
williamr@4
|
86 |
//
|
williamr@4
|
87 |
// real(atanh(z)) == log((1 + x^2 + y^2 + 2x) / (1 + x^2 + y^2 - 2x))
|
williamr@4
|
88 |
//
|
williamr@4
|
89 |
// However, when x is either large (x > 1/E) or very small
|
williamr@4
|
90 |
// (x < E) then this effectively simplifies
|
williamr@4
|
91 |
// to log(1), leading to wildly inaccurate results.
|
williamr@4
|
92 |
// By dividing the above (top and bottom) by (1 + x^2 + y^2) we get:
|
williamr@4
|
93 |
//
|
williamr@4
|
94 |
// real(atanh(z)) == log((1 + (2x / (1 + x^2 + y^2))) / (1 - (-2x / (1 + x^2 + y^2))))
|
williamr@4
|
95 |
//
|
williamr@4
|
96 |
// which is much more sensitive to the value of x, when x is not near 1
|
williamr@4
|
97 |
// (remember we can compute log(1+x) for small x very accurately).
|
williamr@4
|
98 |
//
|
williamr@4
|
99 |
// The cross-over from one method to the other has to be determined
|
williamr@4
|
100 |
// experimentally, the value used below appears correct to within a
|
williamr@4
|
101 |
// factor of 2 (and there are larger errors from other parts
|
williamr@4
|
102 |
// of the input domain anyway).
|
williamr@4
|
103 |
//
|
williamr@4
|
104 |
T alpha = two*x / (one + xx + yy);
|
williamr@4
|
105 |
if(alpha < a_crossover)
|
williamr@4
|
106 |
{
|
williamr@4
|
107 |
real = boost::math::log1p(alpha) - boost::math::log1p(-alpha);
|
williamr@4
|
108 |
}
|
williamr@4
|
109 |
else
|
williamr@4
|
110 |
{
|
williamr@4
|
111 |
T xm1 = x - one;
|
williamr@4
|
112 |
real = boost::math::log1p(x2 + xx + yy) - std::log(xm1*xm1 + yy);
|
williamr@4
|
113 |
}
|
williamr@4
|
114 |
real /= four;
|
williamr@4
|
115 |
if(z.real() < 0)
|
williamr@4
|
116 |
real = -real;
|
williamr@4
|
117 |
|
williamr@4
|
118 |
imag = std::atan2((y * two), (one - xx - yy));
|
williamr@4
|
119 |
imag /= two;
|
williamr@4
|
120 |
if(z.imag() < 0)
|
williamr@4
|
121 |
imag = -imag;
|
williamr@4
|
122 |
}
|
williamr@4
|
123 |
else
|
williamr@4
|
124 |
{
|
williamr@4
|
125 |
//
|
williamr@4
|
126 |
// This section handles exception cases that would normally cause
|
williamr@4
|
127 |
// underflow or overflow in the main formulas.
|
williamr@4
|
128 |
//
|
williamr@4
|
129 |
// Begin by working out the real part, we need to approximate
|
williamr@4
|
130 |
// alpha = 2x / (1 + x^2 + y^2)
|
williamr@4
|
131 |
// without either overflow or underflow in the squared terms.
|
williamr@4
|
132 |
//
|
williamr@4
|
133 |
T alpha = 0;
|
williamr@4
|
134 |
if(x >= safe_upper)
|
williamr@4
|
135 |
{
|
williamr@4
|
136 |
// this is really a test for infinity,
|
williamr@4
|
137 |
// but we may not have the necessary numeric_limits support:
|
williamr@4
|
138 |
if((x > (std::numeric_limits<T>::max)()) || (y > (std::numeric_limits<T>::max)()))
|
williamr@4
|
139 |
{
|
williamr@4
|
140 |
alpha = 0;
|
williamr@4
|
141 |
}
|
williamr@4
|
142 |
else if(y >= safe_upper)
|
williamr@4
|
143 |
{
|
williamr@4
|
144 |
// Big x and y: divide alpha through by x*y:
|
williamr@4
|
145 |
alpha = (two/y) / (x/y + y/x);
|
williamr@4
|
146 |
}
|
williamr@4
|
147 |
else if(y > one)
|
williamr@4
|
148 |
{
|
williamr@4
|
149 |
// Big x: divide through by x:
|
williamr@4
|
150 |
alpha = two / (x + y*y/x);
|
williamr@4
|
151 |
}
|
williamr@4
|
152 |
else
|
williamr@4
|
153 |
{
|
williamr@4
|
154 |
// Big x small y, as above but neglect y^2/x:
|
williamr@4
|
155 |
alpha = two/x;
|
williamr@4
|
156 |
}
|
williamr@4
|
157 |
}
|
williamr@4
|
158 |
else if(y >= safe_upper)
|
williamr@4
|
159 |
{
|
williamr@4
|
160 |
if(x > one)
|
williamr@4
|
161 |
{
|
williamr@4
|
162 |
// Big y, medium x, divide through by y:
|
williamr@4
|
163 |
alpha = (two*x/y) / (y + x*x/y);
|
williamr@4
|
164 |
}
|
williamr@4
|
165 |
else
|
williamr@4
|
166 |
{
|
williamr@4
|
167 |
// Small x and y, whatever alpha is, it's too small to calculate:
|
williamr@4
|
168 |
alpha = 0;
|
williamr@4
|
169 |
}
|
williamr@4
|
170 |
}
|
williamr@4
|
171 |
else
|
williamr@4
|
172 |
{
|
williamr@4
|
173 |
// one or both of x and y are small, calculate divisor carefully:
|
williamr@4
|
174 |
T div = one;
|
williamr@4
|
175 |
if(x > safe_lower)
|
williamr@4
|
176 |
div += x*x;
|
williamr@4
|
177 |
if(y > safe_lower)
|
williamr@4
|
178 |
div += y*y;
|
williamr@4
|
179 |
alpha = two*x/div;
|
williamr@4
|
180 |
}
|
williamr@4
|
181 |
if(alpha < a_crossover)
|
williamr@4
|
182 |
{
|
williamr@4
|
183 |
real = boost::math::log1p(alpha) - boost::math::log1p(-alpha);
|
williamr@4
|
184 |
}
|
williamr@4
|
185 |
else
|
williamr@4
|
186 |
{
|
williamr@4
|
187 |
// We can only get here as a result of small y and medium sized x,
|
williamr@4
|
188 |
// we can simply neglect the y^2 terms:
|
williamr@4
|
189 |
BOOST_ASSERT(x >= safe_lower);
|
williamr@4
|
190 |
BOOST_ASSERT(x <= safe_upper);
|
williamr@4
|
191 |
//BOOST_ASSERT(y <= safe_lower);
|
williamr@4
|
192 |
T xm1 = x - one;
|
williamr@4
|
193 |
real = std::log(1 + two*x + x*x) - std::log(xm1*xm1);
|
williamr@4
|
194 |
}
|
williamr@4
|
195 |
|
williamr@4
|
196 |
real /= four;
|
williamr@4
|
197 |
if(z.real() < 0)
|
williamr@4
|
198 |
real = -real;
|
williamr@4
|
199 |
|
williamr@4
|
200 |
//
|
williamr@4
|
201 |
// Now handle imaginary part, this is much easier,
|
williamr@4
|
202 |
// if x or y are large, then the formula:
|
williamr@4
|
203 |
// atan2(2y, 1 - x^2 - y^2)
|
williamr@4
|
204 |
// evaluates to +-(PI - theta) where theta is negligible compared to PI.
|
williamr@4
|
205 |
//
|
williamr@4
|
206 |
if((x >= safe_upper) || (y >= safe_upper))
|
williamr@4
|
207 |
{
|
williamr@4
|
208 |
imag = pi;
|
williamr@4
|
209 |
}
|
williamr@4
|
210 |
else if(x <= safe_lower)
|
williamr@4
|
211 |
{
|
williamr@4
|
212 |
//
|
williamr@4
|
213 |
// If both x and y are small then atan(2y),
|
williamr@4
|
214 |
// otherwise just x^2 is negligible in the divisor:
|
williamr@4
|
215 |
//
|
williamr@4
|
216 |
if(y <= safe_lower)
|
williamr@4
|
217 |
imag = std::atan2(two*y, one);
|
williamr@4
|
218 |
else
|
williamr@4
|
219 |
{
|
williamr@4
|
220 |
if((y == zero) && (x == zero))
|
williamr@4
|
221 |
imag = 0;
|
williamr@2
|
222 |
else
|
williamr@4
|
223 |
imag = std::atan2(two*y, one - y*y);
|
williamr@4
|
224 |
}
|
williamr@4
|
225 |
}
|
williamr@4
|
226 |
else
|
williamr@4
|
227 |
{
|
williamr@4
|
228 |
//
|
williamr@4
|
229 |
// y^2 is negligible:
|
williamr@4
|
230 |
//
|
williamr@4
|
231 |
if((y == zero) && (x == one))
|
williamr@4
|
232 |
imag = 0;
|
williamr@4
|
233 |
else
|
williamr@4
|
234 |
imag = std::atan2(two*y, 1 - x*x);
|
williamr@4
|
235 |
}
|
williamr@4
|
236 |
imag /= two;
|
williamr@4
|
237 |
if(z.imag() < 0)
|
williamr@4
|
238 |
imag = -imag;
|
williamr@4
|
239 |
}
|
williamr@4
|
240 |
return std::complex<T>(real, imag);
|
williamr@2
|
241 |
}
|
williamr@2
|
242 |
|
williamr@4
|
243 |
} } // namespaces
|
williamr@2
|
244 |
|
williamr@4
|
245 |
#endif // BOOST_MATH_COMPLEX_ATANH_INCLUDED
|