| 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()))
|
|---|