1 | --- boost-trunk/boost/math/complex/atanh.hpp 2012-08-26 18:24:02.000000000 +0000
|
---|
2 | +++ boost-trunk-new/boost/math/complex/atanh.hpp 2012-08-26 21:32:41.000000000 +0000
|
---|
3 | @@ -43,7 +43,7 @@
|
---|
4 | static const T two = static_cast<T>(2.0L);
|
---|
5 | static const T four = static_cast<T>(4.0L);
|
---|
6 | static const T zero = static_cast<T>(0);
|
---|
7 | - static const T a_crossover = static_cast<T>(0.3L);
|
---|
8 | + static const T log_two = boost::math::constants::ln_two<T>();
|
---|
9 |
|
---|
10 | #ifdef BOOST_MSVC
|
---|
11 | #pragma warning(push)
|
---|
12 | @@ -82,45 +82,19 @@
|
---|
13 | else if((x > safe_lower) && (x < safe_upper) && (y > safe_lower) && (y < safe_upper))
|
---|
14 | {
|
---|
15 |
|
---|
16 | - T xx = x*x;
|
---|
17 | T yy = y*y;
|
---|
18 | - T x2 = x * two;
|
---|
19 | -
|
---|
20 | + T mxm1 = one - x;
|
---|
21 | ///
|
---|
22 | // The real part is given by:
|
---|
23 | //
|
---|
24 | - // real(atanh(z)) == log((1 + x^2 + y^2 + 2x) / (1 + x^2 + y^2 - 2x))
|
---|
25 | + // real(atanh(z)) == log1p(4*x / ((x-1)*(x-1) + y^2))
|
---|
26 | //
|
---|
27 | - // However, when x is either large (x > 1/E) or very small
|
---|
28 | - // (x < E) then this effectively simplifies
|
---|
29 | - // to log(1), leading to wildly inaccurate results.
|
---|
30 | - // By dividing the above (top and bottom) by (1 + x^2 + y^2) we get:
|
---|
31 | - //
|
---|
32 | - // real(atanh(z)) == log((1 + (2x / (1 + x^2 + y^2))) / (1 - (-2x / (1 + x^2 + y^2))))
|
---|
33 | - //
|
---|
34 | - // which is much more sensitive to the value of x, when x is not near 1
|
---|
35 | - // (remember we can compute log(1+x) for small x very accurately).
|
---|
36 | - //
|
---|
37 | - // The cross-over from one method to the other has to be determined
|
---|
38 | - // experimentally, the value used below appears correct to within a
|
---|
39 | - // factor of 2 (and there are larger errors from other parts
|
---|
40 | - // of the input domain anyway).
|
---|
41 | - //
|
---|
42 | - T alpha = two*x / (one + xx + yy);
|
---|
43 | - if(alpha < a_crossover)
|
---|
44 | - {
|
---|
45 | - real = boost::math::log1p(alpha) - boost::math::log1p((boost::math::changesign)(alpha));
|
---|
46 | - }
|
---|
47 | - else
|
---|
48 | - {
|
---|
49 | - T xm1 = x - one;
|
---|
50 | - real = boost::math::log1p(x2 + xx + yy) - std::log(xm1*xm1 + yy);
|
---|
51 | - }
|
---|
52 | + real = boost::math::log1p(four * x / (mxm1*mxm1 + yy));
|
---|
53 | real /= four;
|
---|
54 | if((boost::math::signbit)(z.real()))
|
---|
55 | real = (boost::math::changesign)(real);
|
---|
56 |
|
---|
57 | - imag = std::atan2((y * two), (one - xx - yy));
|
---|
58 | + imag = std::atan2((y * two), (mxm1*(one+x) - yy));
|
---|
59 | imag /= two;
|
---|
60 | if(z.imag() < 0)
|
---|
61 | imag = (boost::math::changesign)(imag);
|
---|
62 | @@ -132,30 +106,31 @@
|
---|
63 | // underflow or overflow in the main formulas.
|
---|
64 | //
|
---|
65 | // Begin by working out the real part, we need to approximate
|
---|
66 | - // alpha = 2x / (1 + x^2 + y^2)
|
---|
67 | + // real = boost::math::log1p(4x / ((x-1)^2 + y^2))
|
---|
68 | // without either overflow or underflow in the squared terms.
|
---|
69 | //
|
---|
70 | - T alpha = 0;
|
---|
71 | + T mxm1 = one - x;
|
---|
72 | if(x >= safe_upper)
|
---|
73 | {
|
---|
74 | + // x-1 = x to machine precision:
|
---|
75 | if((boost::math::isinf)(x) || (boost::math::isinf)(y))
|
---|
76 | {
|
---|
77 | - alpha = 0;
|
---|
78 | + real = 0;
|
---|
79 | }
|
---|
80 | else if(y >= safe_upper)
|
---|
81 | {
|
---|
82 | - // Big x and y: divide alpha through by x*y:
|
---|
83 | - alpha = (two/y) / (x/y + y/x);
|
---|
84 | + // Big x and y: divide through by x*y:
|
---|
85 | + real = boost::math::log1p((four/y) / (x/y + y/x));
|
---|
86 | }
|
---|
87 | else if(y > one)
|
---|
88 | {
|
---|
89 | // Big x: divide through by x:
|
---|
90 | - alpha = two / (x + y*y/x);
|
---|
91 | + real = boost::math::log1p(four / (x + y*y/x));
|
---|
92 | }
|
---|
93 | else
|
---|
94 | {
|
---|
95 | // Big x small y, as above but neglect y^2/x:
|
---|
96 | - alpha = two/x;
|
---|
97 | + real = boost::math::log1p(four/x);
|
---|
98 | }
|
---|
99 | }
|
---|
100 | else if(y >= safe_upper)
|
---|
101 | @@ -163,39 +138,25 @@
|
---|
102 | if(x > one)
|
---|
103 | {
|
---|
104 | // Big y, medium x, divide through by y:
|
---|
105 | - alpha = (two*x/y) / (y + x*x/y);
|
---|
106 | + real = boost::math::log1p((four*x/y) / (y + mxm1*mxm1/y));
|
---|
107 | }
|
---|
108 | else
|
---|
109 | {
|
---|
110 | - // Small x and y, whatever alpha is, it's too small to calculate:
|
---|
111 | - alpha = 0;
|
---|
112 | + // Small or medium x, large y:
|
---|
113 | + real = four*x/y/y;
|
---|
114 | }
|
---|
115 | }
|
---|
116 | - else
|
---|
117 | + else if (x != one)
|
---|
118 | {
|
---|
119 | - // one or both of x and y are small, calculate divisor carefully:
|
---|
120 | - T div = one;
|
---|
121 | - if(x > safe_lower)
|
---|
122 | - div += x*x;
|
---|
123 | + // y is small, calculate divisor carefully:
|
---|
124 | + T div = mxm1*mxm1;
|
---|
125 | if(y > safe_lower)
|
---|
126 | div += y*y;
|
---|
127 | - alpha = two*x/div;
|
---|
128 | - }
|
---|
129 | - if(alpha < a_crossover)
|
---|
130 | - {
|
---|
131 | - real = boost::math::log1p(alpha) - boost::math::log1p((boost::math::changesign)(alpha));
|
---|
132 | + real = boost::math::log1p(four*x/div);
|
---|
133 | }
|
---|
134 | else
|
---|
135 | - {
|
---|
136 | - // We can only get here as a result of small y and medium sized x,
|
---|
137 | - // we can simply neglect the y^2 terms:
|
---|
138 | - BOOST_ASSERT(x >= safe_lower);
|
---|
139 | - BOOST_ASSERT(x <= safe_upper);
|
---|
140 | - //BOOST_ASSERT(y <= safe_lower);
|
---|
141 | - T xm1 = x - one;
|
---|
142 | - real = std::log(1 + two*x + x*x) - std::log(xm1*xm1);
|
---|
143 | - }
|
---|
144 | -
|
---|
145 | + real = boost::math::changesign(two * (std::log(y) - log_two));
|
---|
146 | +
|
---|
147 | real /= four;
|
---|
148 | if((boost::math::signbit)(z.real()))
|
---|
149 | real = (boost::math::changesign)(real);
|
---|
150 | @@ -203,7 +164,7 @@
|
---|
151 | //
|
---|
152 | // Now handle imaginary part, this is much easier,
|
---|
153 | // if x or y are large, then the formula:
|
---|
154 | - // atan2(2y, 1 - x^2 - y^2)
|
---|
155 | + // atan2(2y, (1-x)*(1+x) - y^2)
|
---|
156 | // evaluates to +-(PI - theta) where theta is negligible compared to PI.
|
---|
157 | //
|
---|
158 | if((x >= safe_upper) || (y >= safe_upper))
|
---|
159 | @@ -234,7 +195,7 @@
|
---|
160 | if((y == zero) && (x == one))
|
---|
161 | imag = 0;
|
---|
162 | else
|
---|
163 | - imag = std::atan2(two*y, 1 - x*x);
|
---|
164 | + imag = std::atan2(two*y, mxm1*(one+x));
|
---|
165 | }
|
---|
166 | imag /= two;
|
---|
167 | if((boost::math::signbit)(z.imag()))
|
---|