Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:38:48

0001 
0002 // Copyright Christopher Kormanyos 2002 - 2013.
0003 // Copyright 2011 - 2013 John Maddock.
0004 // Distributed under the Boost Software License, Version 1.0.
0005 //    (See accompanying file LICENSE_1_0.txt or copy at
0006 //          http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 // This work is based on an earlier work:
0009 // "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
0010 // in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
0011 //
0012 // This file has no include guards or namespaces - it's expanded inline inside default_ops.hpp
0013 //
0014 
0015 #ifdef BOOST_MSVC
0016 #pragma warning(push)
0017 #pragma warning(disable : 6326) // comparison of two constants
0018 #pragma warning(disable : 4127) // conditional expression is constant
0019 #endif
0020 
0021 #include <boost/multiprecision/detail/standalone_config.hpp>
0022 #include <boost/multiprecision/detail/no_exceptions_support.hpp>
0023 #include <boost/multiprecision/detail/assert.hpp>
0024 
0025 namespace detail {
0026 
0027 template <typename T, typename U>
0028 inline void pow_imp(T& result, const T& t, const U& p, const std::integral_constant<bool, false>&)
0029 {
0030    // Compute the pure power of typename T t^p.
0031    // Use the S-and-X binary method, as described in
0032    // D. E. Knuth, "The Art of Computer Programming", Vol. 2,
0033    // Section 4.6.3 . The resulting computational complexity
0034    // is order log2[abs(p)].
0035 
0036    using int_type = typename boost::multiprecision::detail::canonical<U, T>::type;
0037 
0038    if (&result == &t)
0039    {
0040       T temp;
0041       pow_imp(temp, t, p, std::integral_constant<bool, false>());
0042       result = temp;
0043       return;
0044    }
0045 
0046    switch (p)
0047    {
0048    case 0:
0049       result = int_type(1);
0050       return;
0051    case 1:
0052       result = t;
0053       return;
0054    case 2:
0055       eval_multiply(result, t, t);
0056       return;
0057    case 3:
0058       eval_multiply(result, t, t);
0059       eval_multiply(result, t);
0060       return;
0061    case 4:
0062       eval_multiply(result, t, t);
0063       eval_multiply(result, result);
0064       return;
0065    default:
0066       break;
0067    }
0068 
0069    // This will store the result.
0070    if (U(p % U(2)) != U(0))
0071    {
0072       result = t;
0073    }
0074    else
0075       result = int_type(1);
0076 
0077    U p2(p);
0078 
0079    // The variable x stores the binary powers of t.
0080    T x(t);
0081 
0082    while (U(p2 /= 2) != U(0))
0083    {
0084       // Square x for each binary power.
0085       eval_multiply(x, x);
0086 
0087       const bool has_binary_power = (U(p2 % U(2)) != U(0));
0088 
0089       if (has_binary_power)
0090       {
0091          // Multiply the result with each binary power contained in the exponent.
0092          eval_multiply(result, x);
0093       }
0094    }
0095 }
0096 
0097 template <typename T, typename U>
0098 inline void pow_imp(T& result, const T& t, const U& p, const std::integral_constant<bool, true>&)
0099 {
0100    // Signed integer power, just take care of the sign then call the unsigned version:
0101    using int_type = typename boost::multiprecision::detail::canonical<U, T>::type;
0102    using ui_type = typename boost::multiprecision::detail::make_unsigned<U>::type                         ;
0103 
0104    if (p < 0)
0105    {
0106       T temp;
0107       temp = static_cast<int_type>(1);
0108       T denom;
0109       pow_imp(denom, t, static_cast<ui_type>(-p), std::integral_constant<bool, false>());
0110       eval_divide(result, temp, denom);
0111       return;
0112    }
0113    pow_imp(result, t, static_cast<ui_type>(p), std::integral_constant<bool, false>());
0114 }
0115 
0116 } // namespace detail
0117 
0118 template <typename T, typename U>
0119 inline typename std::enable_if<boost::multiprecision::detail::is_integral<U>::value>::type eval_pow(T& result, const T& t, const U& p)
0120 {
0121    detail::pow_imp(result, t, p, boost::multiprecision::detail::is_signed<U>());
0122 }
0123 
0124 template <class T>
0125 void hyp0F0(T& H0F0, const T& x)
0126 {
0127    // Compute the series representation of Hypergeometric0F0 taken from
0128    // http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F0/06/01/
0129    // There are no checks on input range or parameter boundaries.
0130 
0131    using ui_type = typename std::tuple_element<0, typename T::unsigned_types>::type;
0132 
0133    BOOST_MP_ASSERT(&H0F0 != &x);
0134    long tol = boost::multiprecision::detail::digits2<number<T, et_on> >::value();
0135    T    t;
0136 
0137    T x_pow_n_div_n_fact(x);
0138 
0139    eval_add(H0F0, x_pow_n_div_n_fact, ui_type(1));
0140 
0141    T lim;
0142    eval_ldexp(lim, H0F0, static_cast<int>(1L - tol));
0143    if (eval_get_sign(lim) < 0)
0144       lim.negate();
0145 
0146    ui_type n;
0147 
0148    const unsigned series_limit =
0149        boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
0150            ? 100
0151            : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
0152    // Series expansion of hyperg_0f0(; ; x).
0153    for (n = 2; n < series_limit; ++n)
0154    {
0155       eval_multiply(x_pow_n_div_n_fact, x);
0156       eval_divide(x_pow_n_div_n_fact, n);
0157       eval_add(H0F0, x_pow_n_div_n_fact);
0158       bool neg = eval_get_sign(x_pow_n_div_n_fact) < 0;
0159       if (neg)
0160          x_pow_n_div_n_fact.negate();
0161       if (lim.compare(x_pow_n_div_n_fact) > 0)
0162          break;
0163       if (neg)
0164          x_pow_n_div_n_fact.negate();
0165    }
0166    if (n >= series_limit)
0167       BOOST_MP_THROW_EXCEPTION(std::runtime_error("H0F0 failed to converge"));
0168 }
0169 
0170 template <class T>
0171 void hyp1F0(T& H1F0, const T& a, const T& x)
0172 {
0173    // Compute the series representation of Hypergeometric1F0 taken from
0174    // http://functions.wolfram.com/HypergeometricFunctions/Hypergeometric1F0/06/01/01/
0175    // and also see the corresponding section for the power function (i.e. x^a).
0176    // There are no checks on input range or parameter boundaries.
0177 
0178    using si_type = typename boost::multiprecision::detail::canonical<int, T>::type;
0179 
0180    BOOST_MP_ASSERT(&H1F0 != &x);
0181    BOOST_MP_ASSERT(&H1F0 != &a);
0182 
0183    T x_pow_n_div_n_fact(x);
0184    T pochham_a(a);
0185    T ap(a);
0186 
0187    eval_multiply(H1F0, pochham_a, x_pow_n_div_n_fact);
0188    eval_add(H1F0, si_type(1));
0189    T lim;
0190    eval_ldexp(lim, H1F0, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
0191    if (eval_get_sign(lim) < 0)
0192       lim.negate();
0193 
0194    si_type n;
0195    T       term, part;
0196 
0197    const si_type series_limit =
0198        boost::multiprecision::detail::digits2<number<T, et_on> >::value() < 100
0199            ? 100
0200            : boost::multiprecision::detail::digits2<number<T, et_on> >::value();
0201    // Series expansion of hyperg_1f0(a; ; x).
0202    for (n = 2; n < series_limit; n++)
0203    {
0204       eval_multiply(x_pow_n_div_n_fact, x);
0205       eval_divide(x_pow_n_div_n_fact, n);
0206       eval_increment(ap);
0207       eval_multiply(pochham_a, ap);
0208       eval_multiply(term, pochham_a, x_pow_n_div_n_fact);
0209       eval_add(H1F0, term);
0210       if (eval_get_sign(term) < 0)
0211          term.negate();
0212       if (lim.compare(term) >= 0)
0213          break;
0214    }
0215    if (n >= series_limit)
0216       BOOST_MP_THROW_EXCEPTION(std::runtime_error("H1F0 failed to converge"));
0217 }
0218 
0219 template <class T>
0220 void eval_exp(T& result, const T& x)
0221 {
0222    static_assert(number_category<T>::value == number_kind_floating_point, "The exp function is only valid for floating point types.");
0223    if (&x == &result)
0224    {
0225       T temp;
0226       eval_exp(temp, x);
0227       result = temp;
0228       return;
0229    }
0230    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
0231    using si_type = typename boost::multiprecision::detail::canonical<int, T>::type     ;
0232    using exp_type = typename T::exponent_type                                           ;
0233    using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
0234 
0235    // Handle special arguments.
0236    int  type  = eval_fpclassify(x);
0237    bool isneg = eval_get_sign(x) < 0;
0238    if (type == static_cast<int>(FP_NAN))
0239    {
0240       result = x;
0241       errno  = EDOM;
0242       return;
0243    }
0244    else if (type == static_cast<int>(FP_INFINITE))
0245    {
0246       if (isneg)
0247          result = ui_type(0u);
0248       else
0249          result = x;
0250       return;
0251    }
0252    else if (type == static_cast<int>(FP_ZERO))
0253    {
0254       result = ui_type(1);
0255       return;
0256    }
0257 
0258    // Get local copy of argument and force it to be positive.
0259    T xx = x;
0260    T exp_series;
0261    if (isneg)
0262       xx.negate();
0263 
0264    // Check the range of the argument.
0265    if (xx.compare(si_type(1)) <= 0)
0266    {
0267       //
0268       // Use series for exp(x) - 1:
0269       //
0270       T lim;
0271       BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::is_specialized)
0272          lim = std::numeric_limits<number<T, et_on> >::epsilon().backend();
0273       else
0274       {
0275          result = ui_type(1);
0276          eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
0277       }
0278       unsigned k = 2;
0279       exp_series = xx;
0280       result     = si_type(1);
0281       if (isneg)
0282          eval_subtract(result, exp_series);
0283       else
0284          eval_add(result, exp_series);
0285       eval_multiply(exp_series, xx);
0286       eval_divide(exp_series, ui_type(k));
0287       eval_add(result, exp_series);
0288       while (exp_series.compare(lim) > 0)
0289       {
0290          ++k;
0291          eval_multiply(exp_series, xx);
0292          eval_divide(exp_series, ui_type(k));
0293          if (isneg && (k & 1))
0294             eval_subtract(result, exp_series);
0295          else
0296             eval_add(result, exp_series);
0297       }
0298       return;
0299    }
0300 
0301    // Check for pure-integer arguments which can be either signed or unsigned.
0302    typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type ll;
0303    eval_trunc(exp_series, x);
0304    eval_convert_to(&ll, exp_series);
0305    if (x.compare(ll) == 0)
0306    {
0307       detail::pow_imp(result, get_constant_e<T>(), ll, std::integral_constant<bool, true>());
0308       return;
0309    }
0310    else if (exp_series.compare(x) == 0)
0311    {
0312       // We have a value that has no fractional part, but is too large to fit
0313       // in a long long, in this situation the code below will fail, so
0314       // we're just going to assume that this will overflow:
0315       if (isneg)
0316          result = ui_type(0);
0317       else
0318          result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
0319       return;
0320    }
0321 
0322    // The algorithm for exp has been taken from MPFUN.
0323    // exp(t) = [ (1 + r + r^2/2! + r^3/3! + r^4/4! ...)^p2 ] * 2^n
0324    // where p2 is a power of 2 such as 2048, r = t_prime / p2, and
0325    // t_prime = t - n*ln2, with n chosen to minimize the absolute
0326    // value of t_prime. In the resulting Taylor series, which is
0327    // implemented as a hypergeometric function, |r| is bounded by
0328    // ln2 / p2. For small arguments, no scaling is done.
0329 
0330    // Compute the exponential series of the (possibly) scaled argument.
0331 
0332    eval_divide(result, xx, get_constant_ln2<T>());
0333    exp_type n;
0334    eval_convert_to(&n, result);
0335 
0336    if (n == (std::numeric_limits<exp_type>::max)())
0337    {
0338       // Exponent is too large to fit in our exponent type:
0339       if (isneg)
0340          result = ui_type(0);
0341       else
0342          result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
0343       return;
0344    }
0345 
0346    // The scaling is 2^11 = 2048.
0347    const si_type p2 = static_cast<si_type>(si_type(1) << 11);
0348 
0349    eval_multiply(exp_series, get_constant_ln2<T>(), static_cast<canonical_exp_type>(n));
0350    eval_subtract(exp_series, xx);
0351    eval_divide(exp_series, p2);
0352    exp_series.negate();
0353    hyp0F0(result, exp_series);
0354 
0355    detail::pow_imp(exp_series, result, p2, std::integral_constant<bool, true>());
0356    result = ui_type(1);
0357    eval_ldexp(result, result, n);
0358    eval_multiply(exp_series, result);
0359 
0360    if (isneg)
0361       eval_divide(result, ui_type(1), exp_series);
0362    else
0363       result = exp_series;
0364 }
0365 
0366 template <class T>
0367 void eval_log(T& result, const T& arg)
0368 {
0369    static_assert(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
0370    //
0371    // We use a variation of http://dlmf.nist.gov/4.45#i
0372    // using frexp to reduce the argument to x * 2^n,
0373    // then let y = x - 1 and compute:
0374    // log(x) = log(2) * n + log1p(1 + y)
0375    //
0376    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
0377    using exp_type = typename T::exponent_type                                           ;
0378    using canonical_exp_type = typename boost::multiprecision::detail::canonical<exp_type, T>::type;
0379    using fp_type = typename std::tuple_element<0, typename T::float_types>::type                  ;
0380    int                                                                          s = eval_signbit(arg);
0381    switch (eval_fpclassify(arg))
0382    {
0383    case FP_NAN:
0384       result = arg;
0385       errno  = EDOM;
0386       return;
0387    case FP_INFINITE:
0388       if (s)
0389          break;
0390       result = arg;
0391       return;
0392    case FP_ZERO:
0393       result = std::numeric_limits<number<T> >::has_infinity ? std::numeric_limits<number<T> >::infinity().backend() : (std::numeric_limits<number<T> >::max)().backend();
0394       result.negate();
0395       errno = ERANGE;
0396       return;
0397    default:
0398       break;
0399    }
0400    if (s)
0401    {
0402       result = std::numeric_limits<number<T> >::quiet_NaN().backend();
0403       errno  = EDOM;
0404       return;
0405    }
0406 
0407    exp_type e;
0408    T        t;
0409    eval_frexp(t, arg, &e);
0410    bool alternate = false;
0411 
0412    if (t.compare(fp_type(2) / fp_type(3)) <= 0)
0413    {
0414       alternate = true;
0415       eval_ldexp(t, t, 1);
0416       --e;
0417    }
0418 
0419    eval_multiply(result, get_constant_ln2<T>(), canonical_exp_type(e));
0420    INSTRUMENT_BACKEND(result);
0421    eval_subtract(t, ui_type(1)); /* -0.3 <= t <= 0.3 */
0422    if (!alternate)
0423       t.negate(); /* 0 <= t <= 0.33333 */
0424    T pow = t;
0425    T lim;
0426    T t2;
0427 
0428    if (alternate)
0429       eval_add(result, t);
0430    else
0431       eval_subtract(result, t);
0432 
0433    BOOST_IF_CONSTEXPR(std::numeric_limits<number<T, et_on> >::is_specialized)
0434       eval_multiply(lim, result, std::numeric_limits<number<T, et_on> >::epsilon().backend());
0435    else
0436       eval_ldexp(lim, result, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
0437    if (eval_get_sign(lim) < 0)
0438       lim.negate();
0439    INSTRUMENT_BACKEND(lim);
0440 
0441    ui_type k = 1;
0442    do
0443    {
0444       ++k;
0445       eval_multiply(pow, t);
0446       eval_divide(t2, pow, k);
0447       INSTRUMENT_BACKEND(t2);
0448       if (alternate && ((k & 1) != 0))
0449          eval_add(result, t2);
0450       else
0451          eval_subtract(result, t2);
0452       INSTRUMENT_BACKEND(result);
0453    } while (lim.compare(t2) < 0);
0454 }
0455 
0456 template <class T>
0457 const T& get_constant_log10()
0458 {
0459    static BOOST_MP_THREAD_LOCAL T             result;
0460    static BOOST_MP_THREAD_LOCAL long digits = 0;
0461    if ((digits != boost::multiprecision::detail::digits2<number<T> >::value()))
0462    {
0463       using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
0464       T                                                                            ten;
0465       ten = ui_type(10u);
0466       eval_log(result, ten);
0467       digits = boost::multiprecision::detail::digits2<number<T> >::value();
0468    }
0469 
0470    return result;
0471 }
0472 
0473 template <class T>
0474 void eval_log10(T& result, const T& arg)
0475 {
0476    static_assert(number_category<T>::value == number_kind_floating_point, "The log10 function is only valid for floating point types.");
0477    eval_log(result, arg);
0478    eval_divide(result, get_constant_log10<T>());
0479 }
0480 
0481 template <class R, class T>
0482 inline void eval_log2(R& result, const T& a)
0483 {
0484    eval_log(result, a);
0485    eval_divide(result, get_constant_ln2<R>());
0486 }
0487 
0488 template <typename T>
0489 inline void eval_pow(T& result, const T& x, const T& a)
0490 {
0491    static_assert(number_category<T>::value == number_kind_floating_point, "The pow function is only valid for floating point types.");
0492    using si_type = typename boost::multiprecision::detail::canonical<int, T>::type;
0493    using fp_type = typename std::tuple_element<0, typename T::float_types>::type             ;
0494 
0495    if ((&result == &x) || (&result == &a))
0496    {
0497       T t;
0498       eval_pow(t, x, a);
0499       result = t;
0500       return;
0501    }
0502 
0503    if ((a.compare(si_type(1)) == 0) || (x.compare(si_type(1)) == 0))
0504    {
0505       result = x;
0506       return;
0507    }
0508    if (a.compare(si_type(0)) == 0)
0509    {
0510       result = si_type(1);
0511       return;
0512    }
0513 
0514    int type = eval_fpclassify(x);
0515 
0516    switch (type)
0517    {
0518    case FP_ZERO:
0519       switch (eval_fpclassify(a))
0520       {
0521       case FP_ZERO:
0522          result = si_type(1);
0523          break;
0524       case FP_NAN:
0525          result = a;
0526          break;
0527       case FP_NORMAL: {
0528          // Need to check for a an odd integer as a special case:
0529          BOOST_MP_TRY
0530          {
0531             typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type i;
0532             eval_convert_to(&i, a);
0533             if (a.compare(i) == 0)
0534             {
0535                if (eval_signbit(a))
0536                {
0537                   if (i & 1)
0538                   {
0539                      result = std::numeric_limits<number<T> >::infinity().backend();
0540                      if (eval_signbit(x))
0541                         result.negate();
0542                      errno = ERANGE;
0543                   }
0544                   else
0545                   {
0546                      result = std::numeric_limits<number<T> >::infinity().backend();
0547                      errno  = ERANGE;
0548                   }
0549                }
0550                else if (i & 1)
0551                {
0552                   result = x;
0553                }
0554                else
0555                   result = si_type(0);
0556                return;
0557             }
0558          }
0559          BOOST_MP_CATCH(const std::exception&)
0560          {
0561             // fallthrough..
0562          }
0563          BOOST_MP_CATCH_END
0564          BOOST_FALLTHROUGH;
0565       }
0566       default:
0567          if (eval_signbit(a))
0568          {
0569             result = std::numeric_limits<number<T> >::infinity().backend();
0570             errno  = ERANGE;
0571          }
0572          else
0573             result = x;
0574          break;
0575       }
0576       return;
0577    case FP_NAN:
0578       result = x;
0579       errno  = ERANGE;
0580       return;
0581    default:;
0582    }
0583 
0584    int s = eval_get_sign(a);
0585    if (s == 0)
0586    {
0587       result = si_type(1);
0588       return;
0589    }
0590 
0591    if (s < 0)
0592    {
0593       T t, da;
0594       t = a;
0595       t.negate();
0596       eval_pow(da, x, t);
0597       eval_divide(result, si_type(1), da);
0598       return;
0599    }
0600 
0601    typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type an;
0602    typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type max_an =
0603        std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::is_specialized ? (std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::max)() : static_cast<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>(1) << (sizeof(typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type) * CHAR_BIT - 2);
0604    typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type min_an =
0605        std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::is_specialized ? (std::numeric_limits<typename boost::multiprecision::detail::canonical<std::intmax_t, T>::type>::min)() : -min_an;
0606 
0607    T fa;
0608    BOOST_MP_TRY
0609    {
0610       eval_convert_to(&an, a);
0611       if (a.compare(an) == 0)
0612       {
0613          detail::pow_imp(result, x, an, std::integral_constant<bool, true>());
0614          return;
0615       }
0616    }
0617    BOOST_MP_CATCH(const std::exception&)
0618    {
0619       // conversion failed, just fall through, value is not an integer.
0620       an = (std::numeric_limits<std::intmax_t>::max)();
0621    }
0622    BOOST_MP_CATCH_END
0623    if ((eval_get_sign(x) < 0))
0624    {
0625       typename boost::multiprecision::detail::canonical<std::uintmax_t, T>::type aun;
0626       BOOST_MP_TRY
0627       {
0628          eval_convert_to(&aun, a);
0629          if (a.compare(aun) == 0)
0630          {
0631             fa = x;
0632             fa.negate();
0633             eval_pow(result, fa, a);
0634             if (aun & 1u)
0635                result.negate();
0636             return;
0637          }
0638       }
0639       BOOST_MP_CATCH(const std::exception&)
0640       {
0641          // conversion failed, just fall through, value is not an integer.
0642       }
0643       BOOST_MP_CATCH_END
0644 
0645       eval_floor(result, a);
0646       // -1^INF is a special case in C99:
0647       if ((x.compare(si_type(-1)) == 0) && (eval_fpclassify(a) == FP_INFINITE))
0648       {
0649          result = si_type(1);
0650       }
0651       else if (a.compare(result) == 0)
0652       {
0653          // exponent is so large we have no fractional part:
0654          if (x.compare(si_type(-1)) < 0)
0655          {
0656             result = std::numeric_limits<number<T, et_on> >::infinity().backend();
0657          }
0658          else
0659          {
0660             result = si_type(0);
0661          }
0662       }
0663       else if (type == FP_INFINITE)
0664       {
0665          result = std::numeric_limits<number<T, et_on> >::infinity().backend();
0666       }
0667       else BOOST_IF_CONSTEXPR (std::numeric_limits<number<T, et_on> >::has_quiet_NaN)
0668       {
0669          result = std::numeric_limits<number<T, et_on> >::quiet_NaN().backend();
0670          errno  = EDOM;
0671       }
0672       else
0673       {
0674          BOOST_MP_THROW_EXCEPTION(std::domain_error("Result of pow is undefined or non-real and there is no NaN for this number type."));
0675       }
0676       return;
0677    }
0678 
0679    T t, da;
0680 
0681    eval_subtract(da, a, an);
0682 
0683    if ((x.compare(fp_type(0.5)) >= 0) && (x.compare(fp_type(0.9)) < 0) && (an < max_an) && (an > min_an))
0684    {
0685       if (a.compare(fp_type(1e-5f)) <= 0)
0686       {
0687          // Series expansion for small a.
0688          eval_log(t, x);
0689          eval_multiply(t, a);
0690          hyp0F0(result, t);
0691          return;
0692       }
0693       else
0694       {
0695          // Series expansion for moderately sized x. Note that for large power of a,
0696          // the power of the integer part of a is calculated using the pown function.
0697          if (an)
0698          {
0699             da.negate();
0700             t = si_type(1);
0701             eval_subtract(t, x);
0702             hyp1F0(result, da, t);
0703             detail::pow_imp(t, x, an, std::integral_constant<bool, true>());
0704             eval_multiply(result, t);
0705          }
0706          else
0707          {
0708             da = a;
0709             da.negate();
0710             t = si_type(1);
0711             eval_subtract(t, x);
0712             hyp1F0(result, da, t);
0713          }
0714       }
0715    }
0716    else
0717    {
0718       // Series expansion for pow(x, a). Note that for large power of a, the power
0719       // of the integer part of a is calculated using the pown function.
0720       if (an)
0721       {
0722          eval_log(t, x);
0723          eval_multiply(t, da);
0724          eval_exp(result, t);
0725          detail::pow_imp(t, x, an, std::integral_constant<bool, true>());
0726          eval_multiply(result, t);
0727       }
0728       else
0729       {
0730          eval_log(t, x);
0731          eval_multiply(t, a);
0732          eval_exp(result, t);
0733       }
0734    }
0735 }
0736 
0737 template <class T, class A>
0738 #if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
0739 inline typename std::enable_if<!boost::multiprecision::detail::is_integral<A>::value, void>::type
0740 #else
0741 inline typename std::enable_if<is_compatible_arithmetic_type<A, number<T> >::value && !boost::multiprecision::detail::is_integral<A>::value, void>::type
0742 #endif
0743 eval_pow(T& result, const T& x, const A& a)
0744 {
0745    // Note this one is restricted to float arguments since pow.hpp already has a version for
0746    // integer powers....
0747    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
0748    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
0749    cast_type                                                                      c;
0750    c = a;
0751    eval_pow(result, x, c);
0752 }
0753 
0754 template <class T, class A>
0755 #if BOOST_WORKAROUND(BOOST_MSVC, < 1800)
0756 inline void
0757 #else
0758 inline typename std::enable_if<is_compatible_arithmetic_type<A, number<T> >::value, void>::type
0759 #endif
0760 eval_pow(T& result, const A& x, const T& a)
0761 {
0762    using canonical_type = typename boost::multiprecision::detail::canonical<A, T>::type         ;
0763    using cast_type = typename std::conditional<std::is_same<A, canonical_type>::value, T, canonical_type>::type;
0764    cast_type                                                                      c;
0765    c = x;
0766    eval_pow(result, c, a);
0767 }
0768 
0769 template <class T>
0770 void eval_exp2(T& result, const T& arg)
0771 {
0772    static_assert(number_category<T>::value == number_kind_floating_point, "The log function is only valid for floating point types.");
0773 
0774    // Check for pure-integer arguments which can be either signed or unsigned.
0775    typename boost::multiprecision::detail::canonical<typename T::exponent_type, T>::type i;
0776    T                                                                                     temp;
0777    BOOST_MP_TRY
0778    {
0779       eval_trunc(temp, arg);
0780       eval_convert_to(&i, temp);
0781       if (arg.compare(i) == 0)
0782       {
0783          temp = static_cast<typename std::tuple_element<0, typename T::unsigned_types>::type>(1u);
0784          eval_ldexp(result, temp, i);
0785          return;
0786       }
0787    }
0788    #ifdef BOOST_MP_MATH_AVAILABLE
0789    BOOST_MP_CATCH(const boost::math::rounding_error&)
0790    { /* Fallthrough */
0791    }
0792    #endif
0793    BOOST_MP_CATCH(const std::runtime_error&)
0794    { /* Fallthrough */
0795    }
0796    BOOST_MP_CATCH_END
0797 
0798    temp = static_cast<typename std::tuple_element<0, typename T::unsigned_types>::type>(2u);
0799    eval_pow(result, temp, arg);
0800 }
0801 
0802 namespace detail {
0803 
0804 template <class T>
0805 void small_sinh_series(T x, T& result)
0806 {
0807    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
0808    bool                                                                         neg = eval_get_sign(x) < 0;
0809    if (neg)
0810       x.negate();
0811    T p(x);
0812    T mult(x);
0813    eval_multiply(mult, x);
0814    result    = x;
0815    ui_type k = 1;
0816 
0817    T lim(x);
0818    eval_ldexp(lim, lim, 1 - boost::multiprecision::detail::digits2<number<T, et_on> >::value());
0819 
0820    do
0821    {
0822       eval_multiply(p, mult);
0823       eval_divide(p, ++k);
0824       eval_divide(p, ++k);
0825       eval_add(result, p);
0826    } while (p.compare(lim) >= 0);
0827    if (neg)
0828       result.negate();
0829 }
0830 
0831 template <class T>
0832 void sinhcosh(const T& x, T* p_sinh, T* p_cosh)
0833 {
0834    using ui_type = typename boost::multiprecision::detail::canonical<unsigned, T>::type;
0835    using fp_type = typename std::tuple_element<0, typename T::float_types>::type                  ;
0836 
0837    switch (eval_fpclassify(x))
0838    {
0839    case FP_NAN:
0840       errno = EDOM;
0841       // fallthrough...
0842    case FP_INFINITE:
0843       if (p_sinh)
0844          *p_sinh = x;
0845       if (p_cosh)
0846       {
0847          *p_cosh = x;
0848          if (eval_get_sign(x) < 0)
0849             p_cosh->negate();
0850       }
0851       return;
0852    case FP_ZERO:
0853       if (p_sinh)
0854          *p_sinh = x;
0855       if (p_cosh)
0856          *p_cosh = ui_type(1);
0857       return;
0858    default:;
0859    }
0860 
0861    bool small_sinh = eval_get_sign(x) < 0 ? x.compare(fp_type(-0.5)) > 0 : x.compare(fp_type(0.5)) < 0;
0862 
0863    if (p_cosh || !small_sinh)
0864    {
0865       T e_px, e_mx;
0866       eval_exp(e_px, x);
0867       eval_divide(e_mx, ui_type(1), e_px);
0868       if (eval_signbit(e_mx) != eval_signbit(e_px))
0869          e_mx.negate(); // Handles lack of signed zero in some types
0870 
0871       if (p_sinh)
0872       {
0873          if (small_sinh)
0874          {
0875             small_sinh_series(x, *p_sinh);
0876          }
0877          else
0878          {
0879             eval_subtract(*p_sinh, e_px, e_mx);
0880             eval_ldexp(*p_sinh, *p_sinh, -1);
0881          }
0882       }
0883       if (p_cosh)
0884       {
0885          eval_add(*p_cosh, e_px, e_mx);
0886          eval_ldexp(*p_cosh, *p_cosh, -1);
0887       }
0888    }
0889    else
0890    {
0891       small_sinh_series(x, *p_sinh);
0892    }
0893 }
0894 
0895 } // namespace detail
0896 
0897 template <class T>
0898 inline void eval_sinh(T& result, const T& x)
0899 {
0900    static_assert(number_category<T>::value == number_kind_floating_point, "The sinh function is only valid for floating point types.");
0901    detail::sinhcosh(x, &result, static_cast<T*>(0));
0902 }
0903 
0904 template <class T>
0905 inline void eval_cosh(T& result, const T& x)
0906 {
0907    static_assert(number_category<T>::value == number_kind_floating_point, "The cosh function is only valid for floating point types.");
0908    detail::sinhcosh(x, static_cast<T*>(0), &result);
0909 }
0910 
0911 template <class T>
0912 inline void eval_tanh(T& result, const T& x)
0913 {
0914    static_assert(number_category<T>::value == number_kind_floating_point, "The tanh function is only valid for floating point types.");
0915    T c;
0916    detail::sinhcosh(x, &result, &c);
0917    if ((eval_fpclassify(result) == FP_INFINITE) && (eval_fpclassify(c) == FP_INFINITE))
0918    {
0919       bool s = eval_signbit(result) != eval_signbit(c);
0920       result = static_cast<typename std::tuple_element<0, typename T::unsigned_types>::type>(1u);
0921       if (s)
0922          result.negate();
0923       return;
0924    }
0925    eval_divide(result, c);
0926 }
0927 
0928 #ifdef BOOST_MSVC
0929 #pragma warning(pop)
0930 #endif