epoc32/include/stdapis/boost/math/complex/acos.hpp
branchSymbian2
changeset 2 2fe1408b6811
equal deleted inserted replaced
1:666f914201fb 2:2fe1408b6811
       
     1 //  (C) Copyright John Maddock 2005.
       
     2 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
       
     3 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       
     4 
       
     5 #ifndef BOOST_MATH_COMPLEX_ACOS_INCLUDED
       
     6 #define BOOST_MATH_COMPLEX_ACOS_INCLUDED
       
     7 
       
     8 #ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
       
     9 #  include <boost/math/complex/details.hpp>
       
    10 #endif
       
    11 #ifndef BOOST_MATH_LOG1P_INCLUDED
       
    12 #  include <boost/math/special_functions/log1p.hpp>
       
    13 #endif
       
    14 #include <boost/assert.hpp>
       
    15 
       
    16 #ifdef BOOST_NO_STDC_NAMESPACE
       
    17 namespace std{ using ::sqrt; using ::fabs; using ::acos; using ::asin; using ::atan; using ::atan2; }
       
    18 #endif
       
    19 
       
    20 namespace boost{ namespace math{
       
    21 
       
    22 template<class T> 
       
    23 std::complex<T> acos(const std::complex<T>& z)
       
    24 {
       
    25    //
       
    26    // This implementation is a transcription of the pseudo-code in:
       
    27    //
       
    28    // "Implementing the Complex Arcsine and Arccosine Functions using Exception Handling."
       
    29    // T E Hull, Thomas F Fairgrieve and Ping Tak Peter Tang.
       
    30    // ACM Transactions on Mathematical Software, Vol 23, No 3, Sept 1997.
       
    31    //
       
    32 
       
    33    //
       
    34    // These static constants should really be in a maths constants library:
       
    35    //
       
    36    static const T one = static_cast<T>(1);
       
    37    //static const T two = static_cast<T>(2);
       
    38    static const T half = static_cast<T>(0.5L);
       
    39    static const T a_crossover = static_cast<T>(1.5L);
       
    40    static const T b_crossover = static_cast<T>(0.6417L);
       
    41    static const T s_pi = static_cast<T>(3.141592653589793238462643383279502884197L);
       
    42    static const T half_pi = static_cast<T>(1.57079632679489661923132169163975144L);
       
    43    static const T log_two = static_cast<T>(0.69314718055994530941723212145817657L);
       
    44    static const T quarter_pi = static_cast<T>(0.78539816339744830961566084581987572L);
       
    45    
       
    46    //
       
    47    // Get real and imaginary parts, discard the signs as we can 
       
    48    // figure out the sign of the result later:
       
    49    //
       
    50    T x = std::fabs(z.real());
       
    51    T y = std::fabs(z.imag());
       
    52 
       
    53    T real, imag; // these hold our result
       
    54 
       
    55    // 
       
    56    // Handle special cases specified by the C99 standard,
       
    57    // many of these special cases aren't really needed here,
       
    58    // but doing it this way prevents overflow/underflow arithmetic
       
    59    // in the main body of the logic, which may trip up some machines:
       
    60    //
       
    61    if(std::numeric_limits<T>::has_infinity && (x == std::numeric_limits<T>::infinity()))
       
    62    {
       
    63       if(y == std::numeric_limits<T>::infinity())
       
    64       {
       
    65          real = quarter_pi;
       
    66          imag = std::numeric_limits<T>::infinity();
       
    67       }
       
    68       else if(detail::test_is_nan(y))
       
    69       {
       
    70          return std::complex<T>(y, -std::numeric_limits<T>::infinity());
       
    71       }
       
    72       else
       
    73       {
       
    74          // y is not infinity or nan:
       
    75          real = 0;
       
    76          imag = std::numeric_limits<T>::infinity();
       
    77       }
       
    78    }
       
    79    else if(detail::test_is_nan(x))
       
    80    {
       
    81       if(y == std::numeric_limits<T>::infinity())
       
    82          return std::complex<T>(x, (z.imag() < 0) ? std::numeric_limits<T>::infinity() :  -std::numeric_limits<T>::infinity());
       
    83       return std::complex<T>(x, x);
       
    84    }
       
    85    else if(std::numeric_limits<T>::has_infinity && (y == std::numeric_limits<T>::infinity()))
       
    86    {
       
    87       real = half_pi;
       
    88       imag = std::numeric_limits<T>::infinity();
       
    89    }
       
    90    else if(detail::test_is_nan(y))
       
    91    {
       
    92       return std::complex<T>((x == 0) ? half_pi : y, y);
       
    93    }
       
    94    else
       
    95    {
       
    96       //
       
    97       // What follows is the regular Hull et al code,
       
    98       // begin with the special case for real numbers:
       
    99       //
       
   100       if((y == 0) && (x <= one))
       
   101          return std::complex<T>((x == 0) ? half_pi : std::acos(z.real()));
       
   102       //
       
   103       // Figure out if our input is within the "safe area" identified by Hull et al.
       
   104       // This would be more efficient with portable floating point exception handling;
       
   105       // fortunately the quantities M and u identified by Hull et al (figure 3), 
       
   106       // match with the max and min methods of numeric_limits<T>.
       
   107       //
       
   108       T safe_max = detail::safe_max(static_cast<T>(8));
       
   109       T safe_min = detail::safe_min(static_cast<T>(4));
       
   110 
       
   111       T xp1 = one + x;
       
   112       T xm1 = x - one;
       
   113 
       
   114       if((x < safe_max) && (x > safe_min) && (y < safe_max) && (y > safe_min))
       
   115       {
       
   116          T yy = y * y;
       
   117          T r = std::sqrt(xp1*xp1 + yy);
       
   118          T s = std::sqrt(xm1*xm1 + yy);
       
   119          T a = half * (r + s);
       
   120          T b = x / a;
       
   121 
       
   122          if(b <= b_crossover)
       
   123          {
       
   124             real = std::acos(b);
       
   125          }
       
   126          else
       
   127          {
       
   128             T apx = a + x;
       
   129             if(x <= one)
       
   130             {
       
   131                real = std::atan(std::sqrt(half * apx * (yy /(r + xp1) + (s-xm1)))/x);
       
   132             }
       
   133             else
       
   134             {
       
   135                real = std::atan((y * std::sqrt(half * (apx/(r + xp1) + apx/(s+xm1))))/x);
       
   136             }
       
   137          }
       
   138 
       
   139          if(a <= a_crossover)
       
   140          {
       
   141             T am1;
       
   142             if(x < one)
       
   143             {
       
   144                am1 = half * (yy/(r + xp1) + yy/(s - xm1));
       
   145             }
       
   146             else
       
   147             {
       
   148                am1 = half * (yy/(r + xp1) + (s + xm1));
       
   149             }
       
   150             imag = boost::math::log1p(am1 + std::sqrt(am1 * (a + one)));
       
   151          }
       
   152          else
       
   153          {
       
   154             imag = std::log(a + std::sqrt(a*a - one));
       
   155          }
       
   156       }
       
   157       else
       
   158       {
       
   159          //
       
   160          // This is the Hull et al exception handling code from Fig 6 of their paper:
       
   161          //
       
   162          if(y <= (std::numeric_limits<T>::epsilon() * std::fabs(xm1)))
       
   163          {
       
   164             if(x < one)
       
   165             {
       
   166                real = std::acos(x);
       
   167                imag = y / std::sqrt(xp1*(one-x));
       
   168             }
       
   169             else
       
   170             {
       
   171                real = 0;
       
   172                if(((std::numeric_limits<T>::max)() / xp1) > xm1)
       
   173                {
       
   174                   // xp1 * xm1 won't overflow:
       
   175                   imag = boost::math::log1p(xm1 + std::sqrt(xp1*xm1));
       
   176                }
       
   177                else
       
   178                {
       
   179                   imag = log_two + std::log(x);
       
   180                }
       
   181             }
       
   182          }
       
   183          else if(y <= safe_min)
       
   184          {
       
   185             // There is an assumption in Hull et al's analysis that
       
   186             // if we get here then x == 1.  This is true for all "good"
       
   187             // machines where :
       
   188             // 
       
   189             // E^2 > 8*sqrt(u); with:
       
   190             //
       
   191             // E =  std::numeric_limits<T>::epsilon()
       
   192             // u = (std::numeric_limits<T>::min)()
       
   193             //
       
   194             // Hull et al provide alternative code for "bad" machines
       
   195             // but we have no way to test that here, so for now just assert
       
   196             // on the assumption:
       
   197             //
       
   198             BOOST_ASSERT(x == 1);
       
   199             real = std::sqrt(y);
       
   200             imag = std::sqrt(y);
       
   201          }
       
   202          else if(std::numeric_limits<T>::epsilon() * y - one >= x)
       
   203          {
       
   204             real = half_pi;
       
   205             imag = log_two + std::log(y);
       
   206          }
       
   207          else if(x > one)
       
   208          {
       
   209             real = std::atan(y/x);
       
   210             T xoy = x/y;
       
   211             imag = log_two + std::log(y) + half * boost::math::log1p(xoy*xoy);
       
   212          }
       
   213          else
       
   214          {
       
   215             real = half_pi;
       
   216             T a = std::sqrt(one + y*y);
       
   217             imag = half * boost::math::log1p(static_cast<T>(2)*y*(y+a));
       
   218          }
       
   219       }
       
   220    }
       
   221 
       
   222    //
       
   223    // Finish off by working out the sign of the result:
       
   224    //
       
   225    if(z.real() < 0)
       
   226       real = s_pi - real;
       
   227    if(z.imag() > 0)
       
   228       imag = -imag;
       
   229 
       
   230    return std::complex<T>(real, imag);
       
   231 }
       
   232 
       
   233 } } // namespaces
       
   234 
       
   235 #endif // BOOST_MATH_COMPLEX_ACOS_INCLUDED