Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-15 08:38:19

0001 //  Copyright John Maddock 2006-7, 2013-20.
0002 //  Copyright Paul A. Bristow 2007, 2013-14.
0003 //  Copyright Nikhar Agrawal 2013-14
0004 //  Copyright Christopher Kormanyos 2013-14, 2020, 2024
0005 
0006 //  Use, modification and distribution are subject to the
0007 //  Boost Software License, Version 1.0. (See accompanying file
0008 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 #ifndef BOOST_MATH_SF_GAMMA_HPP
0011 #define BOOST_MATH_SF_GAMMA_HPP
0012 
0013 #ifdef _MSC_VER
0014 #pragma once
0015 #endif
0016 
0017 #include <boost/math/tools/series.hpp>
0018 #include <boost/math/tools/fraction.hpp>
0019 #include <boost/math/tools/precision.hpp>
0020 #include <boost/math/tools/promotion.hpp>
0021 #include <boost/math/tools/assert.hpp>
0022 #include <boost/math/tools/config.hpp>
0023 #include <boost/math/policies/error_handling.hpp>
0024 #include <boost/math/constants/constants.hpp>
0025 #include <boost/math/special_functions/math_fwd.hpp>
0026 #include <boost/math/special_functions/log1p.hpp>
0027 #include <boost/math/special_functions/trunc.hpp>
0028 #include <boost/math/special_functions/powm1.hpp>
0029 #include <boost/math/special_functions/sqrt1pm1.hpp>
0030 #include <boost/math/special_functions/lanczos.hpp>
0031 #include <boost/math/special_functions/fpclassify.hpp>
0032 #include <boost/math/special_functions/detail/igamma_large.hpp>
0033 #include <boost/math/special_functions/detail/unchecked_factorial.hpp>
0034 #include <boost/math/special_functions/detail/lgamma_small.hpp>
0035 #include <boost/math/special_functions/bernoulli.hpp>
0036 #include <boost/math/special_functions/polygamma.hpp>
0037 
0038 #include <cmath>
0039 #include <algorithm>
0040 #include <type_traits>
0041 
0042 #ifdef _MSC_VER
0043 # pragma warning(push)
0044 # pragma warning(disable: 4702) // unreachable code (return after domain_error throw).
0045 # pragma warning(disable: 4127) // conditional expression is constant.
0046 # pragma warning(disable: 4100) // unreferenced formal parameter.
0047 # pragma warning(disable: 6326) // potential comparison of a constant with another constant
0048 // Several variables made comments,
0049 // but some difficulty as whether referenced on not may depend on macro values.
0050 // So to be safe, 4100 warnings suppressed.
0051 // TODO - revisit this?
0052 #endif
0053 
0054 namespace boost{ namespace math{
0055 
0056 namespace detail{
0057 
0058 template <class T>
0059 inline bool is_odd(T v, const std::true_type&)
0060 {
0061    int i = static_cast<int>(v);
0062    return i&1;
0063 }
0064 template <class T>
0065 inline bool is_odd(T v, const std::false_type&)
0066 {
0067    // Oh dear can't cast T to int!
0068    BOOST_MATH_STD_USING
0069    T modulus = v - 2 * floor(v/2);
0070    return static_cast<bool>(modulus != 0);
0071 }
0072 template <class T>
0073 inline bool is_odd(T v)
0074 {
0075    return is_odd(v, ::std::is_convertible<T, int>());
0076 }
0077 
0078 template <class T>
0079 T sinpx(T z)
0080 {
0081    // Ad hoc function calculates x * sin(pi * x),
0082    // taking extra care near when x is near a whole number.
0083    BOOST_MATH_STD_USING
0084    int sign = 1;
0085    if(z < 0)
0086    {
0087       z = -z;
0088    }
0089    T fl = floor(z);
0090    T dist;
0091    if(is_odd(fl))
0092    {
0093       fl += 1;
0094       dist = fl - z;
0095       sign = -sign;
0096    }
0097    else
0098    {
0099       dist = z - fl;
0100    }
0101    BOOST_MATH_ASSERT(fl >= 0);
0102    if(dist > T(0.5))
0103       dist = 1 - dist;
0104    T result = sin(dist*boost::math::constants::pi<T>());
0105    return sign*z*result;
0106 } // template <class T> T sinpx(T z)
0107 //
0108 // tgamma(z), with Lanczos support:
0109 //
0110 template <class T, class Policy, class Lanczos>
0111 T gamma_imp(T z, const Policy& pol, const Lanczos& l)
0112 {
0113    BOOST_MATH_STD_USING
0114 
0115    T result = 1;
0116 
0117 #ifdef BOOST_MATH_INSTRUMENT
0118    static bool b = false;
0119    if(!b)
0120    {
0121       std::cout << "tgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl;
0122       b = true;
0123    }
0124 #endif
0125    static const char* function = "boost::math::tgamma<%1%>(%1%)";
0126 
0127    if(z <= 0)
0128    {
0129       if(floor(z) == z)
0130          return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
0131       if(z <= -20)
0132       {
0133          result = gamma_imp(T(-z), pol, l) * sinpx(z);
0134          BOOST_MATH_INSTRUMENT_VARIABLE(result);
0135          if((fabs(result) < 1) && (tools::max_value<T>() * fabs(result) < boost::math::constants::pi<T>()))
0136             return -boost::math::sign(result) * policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0137          result = -boost::math::constants::pi<T>() / result;
0138          if(result == 0)
0139             return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
0140          if((boost::math::fpclassify)(result) == (int)FP_SUBNORMAL)
0141             return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", result, pol);
0142          BOOST_MATH_INSTRUMENT_VARIABLE(result);
0143          return result;
0144       }
0145 
0146       // shift z to > 1:
0147       while(z < 0)
0148       {
0149          result /= z;
0150          z += 1;
0151       }
0152    }
0153    BOOST_MATH_INSTRUMENT_VARIABLE(result);
0154    if((floor(z) == z) && (z < max_factorial<T>::value))
0155    {
0156       result *= unchecked_factorial<T>(itrunc(z, pol) - 1);
0157       BOOST_MATH_INSTRUMENT_VARIABLE(result);
0158    }
0159    else if (z < tools::root_epsilon<T>())
0160    {
0161       if (z < 1 / tools::max_value<T>())
0162          result = policies::raise_overflow_error<T>(function, nullptr, pol);
0163       result *= 1 / z - constants::euler<T>();
0164    }
0165    else
0166    {
0167       result *= Lanczos::lanczos_sum(z);
0168       T zgh = (z + static_cast<T>(Lanczos::g()) - boost::math::constants::half<T>());
0169       T lzgh = log(zgh);
0170       BOOST_MATH_INSTRUMENT_VARIABLE(result);
0171       BOOST_MATH_INSTRUMENT_VARIABLE(tools::log_max_value<T>());
0172       if(z * lzgh > tools::log_max_value<T>())
0173       {
0174          // we're going to overflow unless this is done with care:
0175          BOOST_MATH_INSTRUMENT_VARIABLE(zgh);
0176          if(lzgh * z / 2 > tools::log_max_value<T>())
0177             return boost::math::sign(result) * policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0178          T hp = pow(zgh, T((z / 2) - T(0.25)));
0179          BOOST_MATH_INSTRUMENT_VARIABLE(hp);
0180          result *= hp / exp(zgh);
0181          BOOST_MATH_INSTRUMENT_VARIABLE(result);
0182          if(tools::max_value<T>() / hp < result)
0183             return boost::math::sign(result) * policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0184          result *= hp;
0185          BOOST_MATH_INSTRUMENT_VARIABLE(result);
0186       }
0187       else
0188       {
0189          BOOST_MATH_INSTRUMENT_VARIABLE(zgh);
0190          BOOST_MATH_INSTRUMENT_VARIABLE(pow(zgh, T(z - boost::math::constants::half<T>())));
0191          BOOST_MATH_INSTRUMENT_VARIABLE(exp(zgh));
0192          result *= pow(zgh, T(z - boost::math::constants::half<T>())) / exp(zgh);
0193          BOOST_MATH_INSTRUMENT_VARIABLE(result);
0194       }
0195    }
0196    return result;
0197 }
0198 //
0199 // lgamma(z) with Lanczos support:
0200 //
0201 template <class T, class Policy, class Lanczos>
0202 T lgamma_imp(T z, const Policy& pol, const Lanczos& l, int* sign = nullptr)
0203 {
0204 #ifdef BOOST_MATH_INSTRUMENT
0205    static bool b = false;
0206    if(!b)
0207    {
0208       std::cout << "lgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl;
0209       b = true;
0210    }
0211 #endif
0212 
0213    BOOST_MATH_STD_USING
0214 
0215    static const char* function = "boost::math::lgamma<%1%>(%1%)";
0216 
0217    T result = 0;
0218    int sresult = 1;
0219    if(z <= -tools::root_epsilon<T>())
0220    {
0221       // reflection formula:
0222       if(floor(z) == z)
0223          return policies::raise_pole_error<T>(function, "Evaluation of lgamma at a negative integer %1%.", z, pol);
0224 
0225       T t = sinpx(z);
0226       z = -z;
0227       if(t < 0)
0228       {
0229          t = -t;
0230       }
0231       else
0232       {
0233          sresult = -sresult;
0234       }
0235       result = log(boost::math::constants::pi<T>()) - lgamma_imp(z, pol, l) - log(t);
0236    }
0237    else if (z < tools::root_epsilon<T>())
0238    {
0239       if (0 == z)
0240          return policies::raise_pole_error<T>(function, "Evaluation of lgamma at %1%.", z, pol);
0241       if (4 * fabs(z) < tools::epsilon<T>())
0242          result = -log(fabs(z));
0243       else
0244          result = log(fabs(1 / z - constants::euler<T>()));
0245       if (z < 0)
0246          sresult = -1;
0247    }
0248    else if(z < 15)
0249    {
0250       typedef typename policies::precision<T, Policy>::type precision_type;
0251       typedef std::integral_constant<int,
0252          precision_type::value <= 0 ? 0 :
0253          precision_type::value <= 64 ? 64 :
0254          precision_type::value <= 113 ? 113 : 0
0255       > tag_type;
0256 
0257       result = lgamma_small_imp<T>(z, T(z - 1), T(z - 2), tag_type(), pol, l);
0258    }
0259    else if((z >= 3) && (z < 100) && (std::numeric_limits<T>::max_exponent >= 1024))
0260    {
0261       // taking the log of tgamma reduces the error, no danger of overflow here:
0262       result = log(gamma_imp(z, pol, l));
0263    }
0264    else
0265    {
0266       // regular evaluation:
0267       T zgh = static_cast<T>(z + T(Lanczos::g()) - boost::math::constants::half<T>());
0268       result = log(zgh) - 1;
0269       result *= z - 0.5f;
0270       //
0271       // Only add on the lanczos sum part if we're going to need it:
0272       //
0273       if(result * tools::epsilon<T>() < 20)
0274          result += log(Lanczos::lanczos_sum_expG_scaled(z));
0275    }
0276 
0277    if(sign)
0278       *sign = sresult;
0279    return result;
0280 }
0281 
0282 //
0283 // Incomplete gamma functions follow:
0284 //
0285 template <class T>
0286 struct upper_incomplete_gamma_fract
0287 {
0288 private:
0289    T z, a;
0290    int k;
0291 public:
0292    typedef std::pair<T,T> result_type;
0293 
0294    upper_incomplete_gamma_fract(T a1, T z1)
0295       : z(z1-a1+1), a(a1), k(0)
0296    {
0297    }
0298 
0299    result_type operator()()
0300    {
0301       ++k;
0302       z += 2;
0303       return result_type(k * (a - k), z);
0304    }
0305 };
0306 
0307 template <class T>
0308 inline T upper_gamma_fraction(T a, T z, T eps)
0309 {
0310    // Multiply result by z^a * e^-z to get the full
0311    // upper incomplete integral.  Divide by tgamma(z)
0312    // to normalise.
0313    upper_incomplete_gamma_fract<T> f(a, z);
0314    return 1 / (z - a + 1 + boost::math::tools::continued_fraction_a(f, eps));
0315 }
0316 
0317 template <class T>
0318 struct lower_incomplete_gamma_series
0319 {
0320 private:
0321    T a, z, result;
0322 public:
0323    typedef T result_type;
0324    lower_incomplete_gamma_series(T a1, T z1) : a(a1), z(z1), result(1){}
0325 
0326    T operator()()
0327    {
0328       T r = result;
0329       a += 1;
0330       result *= z/a;
0331       return r;
0332    }
0333 };
0334 
0335 template <class T, class Policy>
0336 inline T lower_gamma_series(T a, T z, const Policy& pol, T init_value = 0)
0337 {
0338    // Multiply result by ((z^a) * (e^-z) / a) to get the full
0339    // lower incomplete integral. Then divide by tgamma(a)
0340    // to get the normalised value.
0341    lower_incomplete_gamma_series<T> s(a, z);
0342    std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0343    T factor = policies::get_epsilon<T, Policy>();
0344    T result = boost::math::tools::sum_series(s, factor, max_iter, init_value);
0345    policies::check_series_iterations<T>("boost::math::detail::lower_gamma_series<%1%>(%1%)", max_iter, pol);
0346    return result;
0347 }
0348 
0349 //
0350 // Fully generic tgamma and lgamma use Stirling's approximation
0351 // with Bernoulli numbers.
0352 //
0353 template<class T>
0354 std::size_t highest_bernoulli_index()
0355 {
0356    const float digits10_of_type = (std::numeric_limits<T>::is_specialized
0357                                       ? static_cast<float>(std::numeric_limits<T>::digits10)
0358                                       : static_cast<float>(boost::math::tools::digits<T>() * 0.301F));
0359 
0360    // Find the high index n for Bn to produce the desired precision in Stirling's calculation.
0361    return static_cast<std::size_t>(18.0F + (0.6F * digits10_of_type));
0362 }
0363 
0364 template<class T>
0365 int minimum_argument_for_bernoulli_recursion()
0366 {
0367    BOOST_MATH_STD_USING
0368 
0369    const float digits10_of_type = (std::numeric_limits<T>::is_specialized
0370                                     ? (float) std::numeric_limits<T>::digits10
0371                                     : (float) (boost::math::tools::digits<T>() * 0.301F));
0372 
0373    int min_arg = (int) (digits10_of_type * 1.7F);
0374 
0375    if(digits10_of_type < 50.0F)
0376    {
0377       // The following code sequence has been modified
0378       // within the context of issue 396.
0379 
0380       // The calculation of the test-variable limit has now
0381       // been protected against overflow/underflow dangers.
0382 
0383       // The previous line looked like this and did, in fact,
0384       // underflow ldexp when using certain multiprecision types.
0385 
0386       // const float limit = std::ceil(std::pow(1.0f / std::ldexp(1.0f, 1-boost::math::tools::digits<T>()), 1.0f / 20.0f));
0387 
0388       // The new safe version of the limit check is now here.
0389       const float d2_minus_one = ((digits10_of_type / 0.301F) - 1.0F);
0390       const float limit        = ceil(exp((d2_minus_one * log(2.0F)) / 20.0F));
0391 
0392       min_arg = (int) ((std::min)(digits10_of_type * 1.7F, limit));
0393    }
0394 
0395    return min_arg;
0396 }
0397 
0398 template <class T, class Policy>
0399 T scaled_tgamma_no_lanczos(const T& z, const Policy& pol, bool islog = false)
0400 {
0401    BOOST_MATH_STD_USING
0402    //
0403    // Calculates tgamma(z) / (z/e)^z
0404    // Requires that our argument is large enough for Sterling's approximation to hold.
0405    // Used internally when combining gamma's of similar magnitude without logarithms.
0406    //
0407    BOOST_MATH_ASSERT(minimum_argument_for_bernoulli_recursion<T>() <= z);
0408 
0409    // Perform the Bernoulli series expansion of Stirling's approximation.
0410 
0411    const std::size_t number_of_bernoullis_b2n = policies::get_max_series_iterations<Policy>();
0412 
0413    T one_over_x_pow_two_n_minus_one = 1 / z;
0414    const T one_over_x2 = one_over_x_pow_two_n_minus_one * one_over_x_pow_two_n_minus_one;
0415    T sum = (boost::math::bernoulli_b2n<T>(1) / 2) * one_over_x_pow_two_n_minus_one;
0416    const T target_epsilon_to_break_loop = sum * boost::math::tools::epsilon<T>();
0417    const T half_ln_two_pi_over_z = sqrt(boost::math::constants::two_pi<T>() / z);
0418    T last_term = 2 * sum;
0419 
0420    for (std::size_t n = 2U;; ++n)
0421    {
0422       one_over_x_pow_two_n_minus_one *= one_over_x2;
0423 
0424       const std::size_t n2 = static_cast<std::size_t>(n * 2U);
0425 
0426       const T term = (boost::math::bernoulli_b2n<T>(static_cast<int>(n)) * one_over_x_pow_two_n_minus_one) / (n2 * (n2 - 1U));
0427 
0428       if ((n >= 3U) && (abs(term) < target_epsilon_to_break_loop))
0429       {
0430          // We have reached the desired precision in Stirling's expansion.
0431          // Adding additional terms to the sum of this divergent asymptotic
0432          // expansion will not improve the result.
0433 
0434          // Break from the loop.
0435          break;
0436       }
0437       if (n > number_of_bernoullis_b2n)
0438          return policies::raise_evaluation_error("scaled_tgamma_no_lanczos<%1%>()", "Exceeded maximum series iterations without reaching convergence, best approximation was %1%", T(exp(sum) * half_ln_two_pi_over_z), pol);
0439 
0440       sum += term;
0441 
0442       // Sanity check for divergence:
0443       T fterm = fabs(term);
0444       if(fterm > last_term)
0445          return policies::raise_evaluation_error("scaled_tgamma_no_lanczos<%1%>()", "Series became divergent without reaching convergence, best approximation was %1%", T(exp(sum) * half_ln_two_pi_over_z), pol);
0446       last_term = fterm;
0447    }
0448 
0449    // Complete Stirling's approximation.
0450    T scaled_gamma_value = islog ? T(sum + log(half_ln_two_pi_over_z)) : T(exp(sum) * half_ln_two_pi_over_z);
0451    return scaled_gamma_value;
0452 }
0453 
0454 // Forward declaration of the lgamma_imp template specialization.
0455 template <class T, class Policy>
0456 T lgamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos&, int* sign = nullptr);
0457 
0458 template <class T, class Policy>
0459 T gamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos&)
0460 {
0461    BOOST_MATH_STD_USING
0462 
0463    static const char* function = "boost::math::tgamma<%1%>(%1%)";
0464 
0465    // Check if the argument of tgamma is identically zero.
0466    const bool is_at_zero = (z == 0);
0467 
0468    if((boost::math::isnan)(z) || (is_at_zero) || ((boost::math::isinf)(z) && (z < 0)))
0469       return policies::raise_domain_error<T>(function, "Evaluation of tgamma at %1%.", z, pol);
0470 
0471    const bool b_neg = (z < 0);
0472 
0473    const bool floor_of_z_is_equal_to_z = (floor(z) == z);
0474 
0475    // Special case handling of small factorials:
0476    if((!b_neg) && floor_of_z_is_equal_to_z && (z < boost::math::max_factorial<T>::value))
0477    {
0478       return boost::math::unchecked_factorial<T>(itrunc(z) - 1);
0479    }
0480 
0481    // Make a local, unsigned copy of the input argument.
0482    T zz((!b_neg) ? z : -z);
0483 
0484    // Special case for ultra-small z:
0485    if(zz < tools::cbrt_epsilon<T>())
0486    {
0487       const T a0(1);
0488       const T a1(boost::math::constants::euler<T>());
0489       const T six_euler_squared((boost::math::constants::euler<T>() * boost::math::constants::euler<T>()) * 6);
0490       const T a2((six_euler_squared -  boost::math::constants::pi_sqr<T>()) / 12);
0491 
0492       const T inverse_tgamma_series = z * ((a2 * z + a1) * z + a0);
0493 
0494       return 1 / inverse_tgamma_series;
0495    }
0496 
0497    // Scale the argument up for the calculation of lgamma,
0498    // and use downward recursion later for the final result.
0499    const int min_arg_for_recursion = minimum_argument_for_bernoulli_recursion<T>();
0500 
0501    int n_recur;
0502 
0503    if(zz < min_arg_for_recursion)
0504    {
0505       n_recur = boost::math::itrunc(min_arg_for_recursion - zz) + 1;
0506 
0507       zz += n_recur;
0508    }
0509    else
0510    {
0511       n_recur = 0;
0512    }
0513    if (!n_recur)
0514    {
0515       if (zz > tools::log_max_value<T>())
0516          return policies::raise_overflow_error<T>(function, nullptr, pol);
0517       if (log(zz) * zz / 2 > tools::log_max_value<T>())
0518          return policies::raise_overflow_error<T>(function, nullptr, pol);
0519    }
0520    T gamma_value = scaled_tgamma_no_lanczos(zz, pol);
0521    T power_term = pow(zz, zz / 2);
0522    T exp_term = exp(-zz);
0523    gamma_value *= (power_term * exp_term);
0524    if(!n_recur && (tools::max_value<T>() / power_term < gamma_value))
0525       return policies::raise_overflow_error<T>(function, nullptr, pol);
0526    gamma_value *= power_term;
0527 
0528    // Rescale the result using downward recursion if necessary.
0529    if(n_recur)
0530    {
0531       // The order of divides is important, if we keep subtracting 1 from zz
0532       // we DO NOT get back to z (cancellation error).  Further if z < epsilon
0533       // we would end up dividing by zero.  Also in order to prevent spurious
0534       // overflow with the first division, we must save dividing by |z| till last,
0535       // so the optimal order of divides is z+1, z+2, z+3...z+n_recur-1,z.
0536       zz = fabs(z) + 1;
0537       for(int k = 1; k < n_recur; ++k)
0538       {
0539          gamma_value /= zz;
0540          zz += 1;
0541       }
0542       gamma_value /= fabs(z);
0543    }
0544 
0545    // Return the result, accounting for possible negative arguments.
0546    if(b_neg)
0547    {
0548       // Provide special error analysis for:
0549       // * arguments in the neighborhood of a negative integer
0550       // * arguments exactly equal to a negative integer.
0551 
0552       // Check if the argument of tgamma is exactly equal to a negative integer.
0553       if(floor_of_z_is_equal_to_z)
0554          return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
0555 
0556       gamma_value *= sinpx(z);
0557 
0558       BOOST_MATH_INSTRUMENT_VARIABLE(gamma_value);
0559 
0560       const bool result_is_too_large_to_represent = (   (abs(gamma_value) < 1)
0561                                                      && ((tools::max_value<T>() * abs(gamma_value)) < boost::math::constants::pi<T>()));
0562 
0563       if(result_is_too_large_to_represent)
0564          return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0565 
0566       gamma_value = -boost::math::constants::pi<T>() / gamma_value;
0567       BOOST_MATH_INSTRUMENT_VARIABLE(gamma_value);
0568 
0569       if(gamma_value == 0)
0570          return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
0571 
0572       if((boost::math::fpclassify)(gamma_value) == static_cast<int>(FP_SUBNORMAL))
0573          return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", gamma_value, pol);
0574    }
0575 
0576    return gamma_value;
0577 }
0578 
0579 template <class T, class Policy>
0580 inline T log_gamma_near_1(const T& z, Policy const& pol)
0581 {
0582    //
0583    // This is for the multiprecision case where there is
0584    // no lanczos support, use a taylor series at z = 1,
0585    // see https://www.wolframalpha.com/input/?i=taylor+series+lgamma(x)+at+x+%3D+1
0586    //
0587    BOOST_MATH_STD_USING // ADL of std names
0588 
0589    BOOST_MATH_ASSERT(fabs(z) < 1);
0590 
0591    T result = -constants::euler<T>() * z;
0592 
0593    T power_term = z * z / 2;
0594    int n = 2;
0595    T term = 0;
0596 
0597    do
0598    {
0599       term = power_term * boost::math::polygamma(n - 1, T(1), pol);
0600       result += term;
0601       ++n;
0602       power_term *= z / n;
0603    } while (fabs(result) * tools::epsilon<T>() < fabs(term));
0604 
0605    return result;
0606 }
0607 
0608 template <class T, class Policy>
0609 T lgamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos&, int* sign)
0610 {
0611    BOOST_MATH_STD_USING
0612 
0613    static const char* function = "boost::math::lgamma<%1%>(%1%)";
0614 
0615    // Check if the argument of lgamma is identically zero.
0616    const bool is_at_zero = (z == 0);
0617 
0618    if(is_at_zero)
0619       return policies::raise_domain_error<T>(function, "Evaluation of lgamma at zero %1%.", z, pol);
0620    if((boost::math::isnan)(z))
0621       return policies::raise_domain_error<T>(function, "Evaluation of lgamma at %1%.", z, pol);
0622    if((boost::math::isinf)(z))
0623       return policies::raise_overflow_error<T>(function, nullptr, pol);
0624 
0625    const bool b_neg = (z < 0);
0626 
0627    const bool floor_of_z_is_equal_to_z = (floor(z) == z);
0628 
0629    // Special case handling of small factorials:
0630    if((!b_neg) && floor_of_z_is_equal_to_z && (z < boost::math::max_factorial<T>::value))
0631    {
0632       if (sign)
0633          *sign = 1;
0634       return log(boost::math::unchecked_factorial<T>(itrunc(z) - 1));
0635    }
0636 
0637    // Make a local, unsigned copy of the input argument.
0638    T zz((!b_neg) ? z : -z);
0639 
0640    const int min_arg_for_recursion = minimum_argument_for_bernoulli_recursion<T>();
0641 
0642    T log_gamma_value;
0643 
0644    if (zz < min_arg_for_recursion)
0645    {
0646       // Here we simply take the logarithm of tgamma(). This is somewhat
0647       // inefficient, but simple. The rationale is that the argument here
0648       // is relatively small and overflow is not expected to be likely.
0649       if (sign)
0650          * sign = 1;
0651       if(fabs(z - 1) < 0.25)
0652       {
0653          log_gamma_value = log_gamma_near_1(T(zz - 1), pol);
0654       }
0655       else if(fabs(z - 2) < 0.25)
0656       {
0657          log_gamma_value = log_gamma_near_1(T(zz - 2), pol) + log(zz - 1);
0658       }
0659       else if (z > -tools::root_epsilon<T>())
0660       {
0661          // Reflection formula may fail if z is very close to zero, let the series
0662          // expansion for tgamma close to zero do the work:
0663          if (sign)
0664             *sign = z < 0 ? -1 : 1;
0665          return log(abs(gamma_imp(z, pol, lanczos::undefined_lanczos())));
0666       }
0667       else
0668       {
0669          // No issue with spurious overflow in reflection formula,
0670          // just fall through to regular code:
0671          T g = gamma_imp(zz, pol, lanczos::undefined_lanczos());
0672          if (sign)
0673          {
0674             *sign = g < 0 ? -1 : 1;
0675          }
0676          log_gamma_value = log(abs(g));
0677       }
0678    }
0679    else
0680    {
0681       // Perform the Bernoulli series expansion of Stirling's approximation.
0682       T sum = scaled_tgamma_no_lanczos(zz, pol, true);
0683       log_gamma_value = zz * (log(zz) - 1) + sum;
0684    }
0685 
0686    int sign_of_result = 1;
0687 
0688    if(b_neg)
0689    {
0690       // Provide special error analysis if the argument is exactly
0691       // equal to a negative integer.
0692 
0693       // Check if the argument of lgamma is exactly equal to a negative integer.
0694       if(floor_of_z_is_equal_to_z)
0695          return policies::raise_pole_error<T>(function, "Evaluation of lgamma at a negative integer %1%.", z, pol);
0696 
0697       T t = sinpx(z);
0698 
0699       if(t < 0)
0700       {
0701          t = -t;
0702       }
0703       else
0704       {
0705          sign_of_result = -sign_of_result;
0706       }
0707 
0708       log_gamma_value = - log_gamma_value
0709                         + log(boost::math::constants::pi<T>())
0710                         - log(t);
0711    }
0712 
0713    if(sign != static_cast<int*>(nullptr)) { *sign = sign_of_result; }
0714 
0715    return log_gamma_value;
0716 }
0717 
0718 //
0719 // This helper calculates tgamma(dz+1)-1 without cancellation errors,
0720 // used by the upper incomplete gamma with z < 1:
0721 //
0722 template <class T, class Policy, class Lanczos>
0723 T tgammap1m1_imp(T dz, Policy const& pol, const Lanczos& l)
0724 {
0725    BOOST_MATH_STD_USING
0726 
0727    typedef typename policies::precision<T,Policy>::type precision_type;
0728 
0729    typedef std::integral_constant<int,
0730       precision_type::value <= 0 ? 0 :
0731       precision_type::value <= 64 ? 64 :
0732       precision_type::value <= 113 ? 113 : 0
0733    > tag_type;
0734 
0735    T result;
0736    if(dz < 0)
0737    {
0738       if(dz < T(-0.5))
0739       {
0740          // Best method is simply to subtract 1 from tgamma:
0741          result = boost::math::tgamma(1+dz, pol) - 1;
0742          BOOST_MATH_INSTRUMENT_CODE(result);
0743       }
0744       else
0745       {
0746          // Use expm1 on lgamma:
0747          result = boost::math::expm1(-boost::math::log1p(dz, pol)
0748             + lgamma_small_imp<T>(dz+2, dz + 1, dz, tag_type(), pol, l), pol);
0749          BOOST_MATH_INSTRUMENT_CODE(result);
0750       }
0751    }
0752    else
0753    {
0754       if(dz < 2)
0755       {
0756          // Use expm1 on lgamma:
0757          result = boost::math::expm1(lgamma_small_imp<T>(dz+1, dz, dz-1, tag_type(), pol, l), pol);
0758          BOOST_MATH_INSTRUMENT_CODE(result);
0759       }
0760       else
0761       {
0762          // Best method is simply to subtract 1 from tgamma:
0763          result = boost::math::tgamma(1+dz, pol) - 1;
0764          BOOST_MATH_INSTRUMENT_CODE(result);
0765       }
0766    }
0767 
0768    return result;
0769 }
0770 
0771 template <class T, class Policy>
0772 inline T tgammap1m1_imp(T z, Policy const& pol,
0773                  const ::boost::math::lanczos::undefined_lanczos&)
0774 {
0775    BOOST_MATH_STD_USING // ADL of std names
0776 
0777    if(fabs(z) < T(0.55))
0778    {
0779       return boost::math::expm1(log_gamma_near_1(z, pol));
0780    }
0781    return boost::math::expm1(boost::math::lgamma(1 + z, pol));
0782 }
0783 
0784 //
0785 // Series representation for upper fraction when z is small:
0786 //
0787 template <class T>
0788 struct small_gamma2_series
0789 {
0790    typedef T result_type;
0791 
0792    small_gamma2_series(T a_, T x_) : result(-x_), x(-x_), apn(a_+1), n(1){}
0793 
0794    T operator()()
0795    {
0796       T r = result / (apn);
0797       result *= x;
0798       result /= ++n;
0799       apn += 1;
0800       return r;
0801    }
0802 
0803 private:
0804    T result, x, apn;
0805    int n;
0806 };
0807 //
0808 // calculate power term prefix (z^a)(e^-z) used in the non-normalised
0809 // incomplete gammas:
0810 //
0811 template <class T, class Policy>
0812 T full_igamma_prefix(T a, T z, const Policy& pol)
0813 {
0814    BOOST_MATH_STD_USING
0815 
0816    if (z > tools::max_value<T>())
0817       return 0;
0818 
0819    T alz = a * log(z);
0820 
0821    T prefix { };
0822 
0823    if(z >= 1)
0824    {
0825       if((alz < tools::log_max_value<T>()) && (-z > tools::log_min_value<T>()))
0826       {
0827          prefix = pow(z, a) * exp(-z);
0828       }
0829       else if(a >= 1)
0830       {
0831          prefix = pow(T(z / exp(z/a)), a);
0832       }
0833       else
0834       {
0835          prefix = exp(alz - z);
0836       }
0837    }
0838    else
0839    {
0840       if(alz > tools::log_min_value<T>())
0841       {
0842          prefix = pow(z, a) * exp(-z);
0843       }
0844       else if(z/a < tools::log_max_value<T>())
0845       {
0846          prefix = pow(T(z / exp(z/a)), a);
0847       }
0848       else
0849       {
0850          prefix = exp(alz - z);
0851       }
0852    }
0853    //
0854    // This error handling isn't very good: it happens after the fact
0855    // rather than before it...
0856    //
0857    if((boost::math::fpclassify)(prefix) == (int)FP_INFINITE)
0858       return policies::raise_overflow_error<T>("boost::math::detail::full_igamma_prefix<%1%>(%1%, %1%)", "Result of incomplete gamma function is too large to represent.", pol);
0859 
0860    return prefix;
0861 }
0862 //
0863 // Compute (z^a)(e^-z)/tgamma(a)
0864 // most if the error occurs in this function:
0865 //
0866 template <class T, class Policy, class Lanczos>
0867 T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l)
0868 {
0869    BOOST_MATH_STD_USING
0870    if (z >= tools::max_value<T>())
0871       return 0;
0872    T agh = a + static_cast<T>(Lanczos::g()) - T(0.5);
0873    T prefix;
0874    T d = ((z - a) - static_cast<T>(Lanczos::g()) + T(0.5)) / agh;
0875 
0876    if(a < 1)
0877    {
0878       //
0879       // We have to treat a < 1 as a special case because our Lanczos
0880       // approximations are optimised against the factorials with a > 1,
0881       // and for high precision types especially (128-bit reals for example)
0882       // very small values of a can give rather erroneous results for gamma
0883       // unless we do this:
0884       //
0885       // TODO: is this still required?  Lanczos approx should be better now?
0886       //
0887       if((z <= tools::log_min_value<T>()) || (a < 1 / tools::max_value<T>()))
0888       {
0889          // Oh dear, have to use logs, should be free of cancellation errors though:
0890          return exp(a * log(z) - z - lgamma_imp(a, pol, l));
0891       }
0892       else
0893       {
0894          // direct calculation, no danger of overflow as gamma(a) < 1/a
0895          // for small a.
0896          return pow(z, a) * exp(-z) / gamma_imp(a, pol, l);
0897       }
0898    }
0899    else if((fabs(d*d*a) <= 100) && (a > 150))
0900    {
0901       // special case for large a and a ~ z.
0902       prefix = a * boost::math::log1pmx(d, pol) + z * static_cast<T>(0.5 - Lanczos::g()) / agh;
0903       prefix = exp(prefix);
0904    }
0905    else
0906    {
0907       //
0908       // general case.
0909       // direct computation is most accurate, but use various fallbacks
0910       // for different parts of the problem domain:
0911       //
0912       T alz = a * log(z / agh);
0913       T amz = a - z;
0914       if(((std::min)(alz, amz) <= tools::log_min_value<T>()) || ((std::max)(alz, amz) >= tools::log_max_value<T>()))
0915       {
0916          T amza = amz / a;
0917          if(((std::min)(alz, amz)/2 > tools::log_min_value<T>()) && ((std::max)(alz, amz)/2 < tools::log_max_value<T>()))
0918          {
0919             // compute square root of the result and then square it:
0920             T sq = pow(z / agh, a / 2) * exp(amz / 2);
0921             prefix = sq * sq;
0922          }
0923          else if(((std::min)(alz, amz)/4 > tools::log_min_value<T>()) && ((std::max)(alz, amz)/4 < tools::log_max_value<T>()) && (z > a))
0924          {
0925             // compute the 4th root of the result then square it twice:
0926             T sq = pow(z / agh, a / 4) * exp(amz / 4);
0927             prefix = sq * sq;
0928             prefix *= prefix;
0929          }
0930          else if((amza > tools::log_min_value<T>()) && (amza < tools::log_max_value<T>()))
0931          {
0932             prefix = pow(T((z * exp(amza)) / agh), a);
0933          }
0934          else
0935          {
0936             prefix = exp(alz + amz);
0937          }
0938       }
0939       else
0940       {
0941          prefix = pow(T(z / agh), a) * exp(amz);
0942       }
0943    }
0944    prefix *= sqrt(agh / boost::math::constants::e<T>()) / Lanczos::lanczos_sum_expG_scaled(a);
0945    return prefix;
0946 }
0947 //
0948 // And again, without Lanczos support:
0949 //
0950 template <class T, class Policy>
0951 T regularised_gamma_prefix(T a, T z, const Policy& pol, const lanczos::undefined_lanczos& l)
0952 {
0953    BOOST_MATH_STD_USING
0954 
0955    if((a < 1) && (z < 1))
0956    {
0957       // No overflow possible since the power terms tend to unity as a,z -> 0
0958       return pow(z, a) * exp(-z) / boost::math::tgamma(a, pol);
0959    }
0960    else if(a > minimum_argument_for_bernoulli_recursion<T>())
0961    {
0962       T scaled_gamma = scaled_tgamma_no_lanczos(a, pol);
0963       T power_term = pow(z / a, a / 2);
0964       T a_minus_z = a - z;
0965       if ((0 == power_term) || (fabs(a_minus_z) > tools::log_max_value<T>()))
0966       {
0967          // The result is probably zero, but we need to be sure:
0968          return exp(a * log(z / a) + a_minus_z - log(scaled_gamma));
0969       }
0970       return (power_term * exp(a_minus_z)) * (power_term / scaled_gamma);
0971    }
0972    else
0973    {
0974       //
0975       // Usual case is to calculate the prefix at a+shift and recurse down
0976       // to the value we want:
0977       //
0978       const int min_z = minimum_argument_for_bernoulli_recursion<T>();
0979       long shift = 1 + ltrunc(min_z - a);
0980       T result = regularised_gamma_prefix(T(a + shift), z, pol, l);
0981       if (result != 0)
0982       {
0983          for (long i = 0; i < shift; ++i)
0984          {
0985             result /= z;
0986             result *= a + i;
0987          }
0988          return result;
0989       }
0990       else
0991       {
0992          //
0993          // We failed, most probably we have z << 1, try again, this time
0994          // we calculate z^a e^-z / tgamma(a+shift), combining power terms
0995          // as we go.  And again recurse down to the result.
0996          //
0997          T scaled_gamma = scaled_tgamma_no_lanczos(T(a + shift), pol);
0998          T power_term_1 = pow(T(z / (a + shift)), a);
0999          T power_term_2 = pow(T(a + shift), T(-shift));
1000          T power_term_3 = exp(a + shift - z);
1001          if ((0 == power_term_1) || (0 == power_term_2) || (0 == power_term_3) || (fabs(a + shift - z) > tools::log_max_value<T>()))
1002          {
1003             // We have no test case that gets here, most likely the type T
1004             // has a high precision but low exponent range:
1005             return exp(a * log(z) - z - boost::math::lgamma(a, pol));
1006          }
1007          result = power_term_1 * power_term_2 * power_term_3 / scaled_gamma;
1008          for (long i = 0; i < shift; ++i)
1009          {
1010             result *= a + i;
1011          }
1012          return result;
1013       }
1014    }
1015 }
1016 //
1017 // Upper gamma fraction for very small a:
1018 //
1019 template <class T, class Policy>
1020 inline T tgamma_small_upper_part(T a, T x, const Policy& pol, T* pgam = 0, bool invert = false, T* pderivative = 0)
1021 {
1022    BOOST_MATH_STD_USING  // ADL of std functions.
1023    //
1024    // Compute the full upper fraction (Q) when a is very small:
1025    //
1026 
1027    T result { boost::math::tgamma1pm1(a, pol) };
1028 
1029    if(pgam)
1030       *pgam = (result + 1) / a;
1031    T p = boost::math::powm1(x, a, pol);
1032    result -= p;
1033    result /= a;
1034    detail::small_gamma2_series<T> s(a, x);
1035    std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>() - 10;
1036    p += 1;
1037    if(pderivative)
1038       *pderivative = p / (*pgam * exp(x));
1039    T init_value = invert ? *pgam : 0;
1040    result = -p * tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, (init_value - result) / p);
1041    policies::check_series_iterations<T>("boost::math::tgamma_small_upper_part<%1%>(%1%, %1%)", max_iter, pol);
1042    if(invert)
1043       result = -result;
1044    return result;
1045 }
1046 //
1047 // Upper gamma fraction for integer a:
1048 //
1049 template <class T, class Policy>
1050 inline T finite_gamma_q(T a, T x, Policy const& pol, T* pderivative = 0)
1051 {
1052    //
1053    // Calculates normalised Q when a is an integer:
1054    //
1055    BOOST_MATH_STD_USING
1056    T e = exp(-x);
1057    T sum = e;
1058    if(sum != 0)
1059    {
1060       T term = sum;
1061       for(unsigned n = 1; n < a; ++n)
1062       {
1063          term /= n;
1064          term *= x;
1065          sum += term;
1066       }
1067    }
1068    if(pderivative)
1069    {
1070       *pderivative = e * pow(x, a) / boost::math::unchecked_factorial<T>(itrunc(T(a - 1), pol));
1071    }
1072    return sum;
1073 }
1074 //
1075 // Upper gamma fraction for half integer a:
1076 //
1077 template <class T, class Policy>
1078 T finite_half_gamma_q(T a, T x, T* p_derivative, const Policy& pol)
1079 {
1080    //
1081    // Calculates normalised Q when a is a half-integer:
1082    //
1083    BOOST_MATH_STD_USING
1084    T e = boost::math::erfc(sqrt(x), pol);
1085    if((e != 0) && (a > 1))
1086    {
1087       T term = exp(-x) / sqrt(constants::pi<T>() * x);
1088       term *= x;
1089       static const T half = T(1) / 2;
1090       term /= half;
1091       T sum = term;
1092       for(unsigned n = 2; n < a; ++n)
1093       {
1094          term /= n - half;
1095          term *= x;
1096          sum += term;
1097       }
1098       e += sum;
1099       if(p_derivative)
1100       {
1101          *p_derivative = 0;
1102       }
1103    }
1104    else if(p_derivative)
1105    {
1106       // We'll be dividing by x later, so calculate derivative * x:
1107       *p_derivative = sqrt(x) * exp(-x) / constants::root_pi<T>();
1108    }
1109    return e;
1110 }
1111 //
1112 // Asymptotic approximation for large argument, see: https://dlmf.nist.gov/8.11#E2
1113 //
1114 template <class T>
1115 struct incomplete_tgamma_large_x_series
1116 {
1117    typedef T result_type;
1118    incomplete_tgamma_large_x_series(const T& a, const T& x)
1119       : a_poch(a - 1), z(x), term(1) {}
1120    T operator()()
1121    {
1122       T result = term;
1123       term *= a_poch / z;
1124       a_poch -= 1;
1125       return result;
1126    }
1127    T a_poch, z, term;
1128 };
1129 
1130 template <class T, class Policy>
1131 T incomplete_tgamma_large_x(const T& a, const T& x, const Policy& pol)
1132 {
1133    BOOST_MATH_STD_USING
1134    incomplete_tgamma_large_x_series<T> s(a, x);
1135    std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
1136    T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
1137    boost::math::policies::check_series_iterations<T>("boost::math::tgamma<%1%>(%1%,%1%)", max_iter, pol);
1138    return result;
1139 }
1140 
1141 
1142 //
1143 // Main incomplete gamma entry point, handles all four incomplete gamma's:
1144 //
1145 template <class T, class Policy>
1146 T gamma_incomplete_imp(T a, T x, bool normalised, bool invert,
1147                        const Policy& pol, T* p_derivative)
1148 {
1149    static const char* function = "boost::math::gamma_p<%1%>(%1%, %1%)";
1150    if(a <= 0)
1151       return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
1152    if(x < 0)
1153       return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
1154 
1155    BOOST_MATH_STD_USING
1156 
1157    typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1158 
1159    T result = 0; // Just to avoid warning C4701: potentially uninitialized local variable 'result' used
1160 
1161    if(a >= max_factorial<T>::value && !normalised)
1162    {
1163       //
1164       // When we're computing the non-normalized incomplete gamma
1165       // and a is large the result is rather hard to compute unless
1166       // we use logs.  There are really two options - if x is a long
1167       // way from a in value then we can reliably use methods 2 and 4
1168       // below in logarithmic form and go straight to the result.
1169       // Otherwise we let the regularized gamma take the strain
1170       // (the result is unlikely to underflow in the central region anyway)
1171       // and combine with lgamma in the hopes that we get a finite result.
1172       //
1173       if(invert && (a * 4 < x))
1174       {
1175          // This is method 4 below, done in logs:
1176          result = a * log(x) - x;
1177          if(p_derivative)
1178             *p_derivative = exp(result);
1179          result += log(upper_gamma_fraction(a, x, policies::get_epsilon<T, Policy>()));
1180       }
1181       else if(!invert && (a > 4 * x))
1182       {
1183          // This is method 2 below, done in logs:
1184          result = a * log(x) - x;
1185          if(p_derivative)
1186             *p_derivative = exp(result);
1187          T init_value = 0;
1188          result += log(detail::lower_gamma_series(a, x, pol, init_value) / a);
1189       }
1190       else
1191       {
1192          result = gamma_incomplete_imp(a, x, true, invert, pol, p_derivative);
1193          if(result == 0)
1194          {
1195             if(invert)
1196             {
1197                // Try http://functions.wolfram.com/06.06.06.0039.01
1198                result = 1 + 1 / (12 * a) + 1 / (288 * a * a);
1199                result = log(result) - a + (a - 0.5f) * log(a) + log(boost::math::constants::root_two_pi<T>());
1200                if(p_derivative)
1201                   *p_derivative = exp(a * log(x) - x);
1202             }
1203             else
1204             {
1205                // This is method 2 below, done in logs, we're really outside the
1206                // range of this method, but since the result is almost certainly
1207                // infinite, we should probably be OK:
1208                result = a * log(x) - x;
1209                if(p_derivative)
1210                   *p_derivative = exp(result);
1211                T init_value = 0;
1212                result += log(detail::lower_gamma_series(a, x, pol, init_value) / a);
1213             }
1214          }
1215          else
1216          {
1217             result = log(result) + boost::math::lgamma(a, pol);
1218          }
1219       }
1220       if(result > tools::log_max_value<T>())
1221          return policies::raise_overflow_error<T>(function, nullptr, pol);
1222       return exp(result);
1223    }
1224 
1225    BOOST_MATH_ASSERT((p_derivative == nullptr) || normalised);
1226 
1227    bool is_int, is_half_int;
1228    bool is_small_a = (a < 30) && (a <= x + 1) && (x < tools::log_max_value<T>());
1229    if(is_small_a)
1230    {
1231       T fa = floor(a);
1232       is_int = (fa == a);
1233       is_half_int = is_int ? false : (fabs(fa - a) == 0.5f);
1234    }
1235    else
1236    {
1237       is_int = is_half_int = false;
1238    }
1239 
1240    int eval_method;
1241 
1242    if(is_int && (x > 0.6))
1243    {
1244       // calculate Q via finite sum:
1245       invert = !invert;
1246       eval_method = 0;
1247    }
1248    else if(is_half_int && (x > 0.2))
1249    {
1250       // calculate Q via finite sum for half integer a:
1251       invert = !invert;
1252       eval_method = 1;
1253    }
1254    else if((x < tools::root_epsilon<T>()) && (a > 1))
1255    {
1256       eval_method = 6;
1257    }
1258    else if ((x > 1000) && ((a < x) || (fabs(a - 50) / x < 1)))
1259    {
1260       // calculate Q via asymptotic approximation:
1261       invert = !invert;
1262       eval_method = 7;
1263    }
1264    else if(x < T(0.5))
1265    {
1266       //
1267       // Changeover criterion chosen to give a changeover at Q ~ 0.33
1268       //
1269       if(T(-0.4) / log(x) < a)
1270       {
1271          eval_method = 2;
1272       }
1273       else
1274       {
1275          eval_method = 3;
1276       }
1277    }
1278    else if(x < T(1.1))
1279    {
1280       //
1281       // Changeover here occurs when P ~ 0.75 or Q ~ 0.25:
1282       //
1283       if(x * 0.75f < a)
1284       {
1285          eval_method = 2;
1286       }
1287       else
1288       {
1289          eval_method = 3;
1290       }
1291    }
1292    else
1293    {
1294       //
1295       // Begin by testing whether we're in the "bad" zone
1296       // where the result will be near 0.5 and the usual
1297       // series and continued fractions are slow to converge:
1298       //
1299       bool use_temme = false;
1300       if(normalised && std::numeric_limits<T>::is_specialized && (a > 20))
1301       {
1302          T sigma = fabs((x-a)/a);
1303          if((a > 200) && (policies::digits<T, Policy>() <= 113))
1304          {
1305             //
1306             // This limit is chosen so that we use Temme's expansion
1307             // only if the result would be larger than about 10^-6.
1308             // Below that the regular series and continued fractions
1309             // converge OK, and if we use Temme's method we get increasing
1310             // errors from the dominant erfc term as it's (inexact) argument
1311             // increases in magnitude.
1312             //
1313             if(20 / a > sigma * sigma)
1314                use_temme = true;
1315          }
1316          else if(policies::digits<T, Policy>() <= 64)
1317          {
1318             // Note in this zone we can't use Temme's expansion for
1319             // types longer than an 80-bit real:
1320             // it would require too many terms in the polynomials.
1321             if(sigma < 0.4)
1322                use_temme = true;
1323          }
1324       }
1325       if(use_temme)
1326       {
1327          eval_method = 5;
1328       }
1329       else
1330       {
1331          //
1332          // Regular case where the result will not be too close to 0.5.
1333          //
1334          // Changeover here occurs at P ~ Q ~ 0.5
1335          // Note that series computation of P is about x2 faster than continued fraction
1336          // calculation of Q, so try and use the CF only when really necessary, especially
1337          // for small x.
1338          //
1339          if(x - (1 / (3 * x)) < a)
1340          {
1341             eval_method = 2;
1342          }
1343          else
1344          {
1345             eval_method = 4;
1346             invert = !invert;
1347          }
1348       }
1349    }
1350 
1351    switch(eval_method)
1352    {
1353    case 0:
1354       {
1355          result = finite_gamma_q(a, x, pol, p_derivative);
1356          if(!normalised)
1357             result *= boost::math::tgamma(a, pol);
1358          break;
1359       }
1360    case 1:
1361       {
1362          result = finite_half_gamma_q(a, x, p_derivative, pol);
1363          if(!normalised)
1364             result *= boost::math::tgamma(a, pol);
1365          if(p_derivative && (*p_derivative == 0))
1366             *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1367          break;
1368       }
1369    case 2:
1370       {
1371          // Compute P:
1372          result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1373          if(p_derivative)
1374             *p_derivative = result;
1375          if(result != 0)
1376          {
1377             //
1378             // If we're going to be inverting the result then we can
1379             // reduce the number of series evaluations by quite
1380             // a few iterations if we set an initial value for the
1381             // series sum based on what we'll end up subtracting it from
1382             // at the end.
1383             // Have to be careful though that this optimization doesn't
1384             // lead to spurious numeric overflow.  Note that the
1385             // scary/expensive overflow checks below are more often
1386             // than not bypassed in practice for "sensible" input
1387             // values:
1388             //
1389             T init_value = 0;
1390             bool optimised_invert = false;
1391             if(invert)
1392             {
1393                init_value = (normalised ? 1 : boost::math::tgamma(a, pol));
1394                if(normalised || (result >= 1) || (tools::max_value<T>() * result > init_value))
1395                {
1396                   init_value /= result;
1397                   if(normalised || (a < 1) || (tools::max_value<T>() / a > init_value))
1398                   {
1399                      init_value *= -a;
1400                      optimised_invert = true;
1401                   }
1402                   else
1403                      init_value = 0;
1404                }
1405                else
1406                   init_value = 0;
1407             }
1408             result *= detail::lower_gamma_series(a, x, pol, init_value) / a;
1409             if(optimised_invert)
1410             {
1411                invert = false;
1412                result = -result;
1413             }
1414          }
1415          break;
1416       }
1417    case 3:
1418       {
1419          // Compute Q:
1420          invert = !invert;
1421          T g;
1422          result = tgamma_small_upper_part(a, x, pol, &g, invert, p_derivative);
1423          invert = false;
1424          if(normalised)
1425             result /= g;
1426          break;
1427       }
1428    case 4:
1429       {
1430          // Compute Q:
1431          result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1432          if(p_derivative)
1433             *p_derivative = result;
1434          if(result != 0)
1435             result *= upper_gamma_fraction(a, x, policies::get_epsilon<T, Policy>());
1436          break;
1437       }
1438    case 5:
1439       {
1440          //
1441          // Use compile time dispatch to the appropriate
1442          // Temme asymptotic expansion.  This may be dead code
1443          // if T does not have numeric limits support, or has
1444          // too many digits for the most precise version of
1445          // these expansions, in that case we'll be calling
1446          // an empty function.
1447          //
1448          typedef typename policies::precision<T, Policy>::type precision_type;
1449 
1450          typedef std::integral_constant<int,
1451             precision_type::value <= 0 ? 0 :
1452             precision_type::value <= 53 ? 53 :
1453             precision_type::value <= 64 ? 64 :
1454             precision_type::value <= 113 ? 113 : 0
1455          > tag_type;
1456 
1457          result = igamma_temme_large(a, x, pol, static_cast<tag_type const*>(nullptr));
1458          if(x >= a)
1459             invert = !invert;
1460          if(p_derivative)
1461             *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1462          break;
1463       }
1464    case 6:
1465       {
1466          // x is so small that P is necessarily very small too,
1467          // use http://functions.wolfram.com/GammaBetaErf/GammaRegularized/06/01/05/01/01/
1468          if(!normalised)
1469             result = pow(x, a) / (a);
1470          else
1471          {
1472 #ifndef BOOST_MATH_NO_EXCEPTIONS
1473             try
1474             {
1475 #endif
1476                result = pow(x, a) / boost::math::tgamma(a + 1, pol);
1477 #ifndef BOOST_MATH_NO_EXCEPTIONS
1478             }
1479             catch (const std::overflow_error&)
1480             {
1481                result = 0;
1482             }
1483 #endif
1484          }
1485          result *= 1 - a * x / (a + 1);
1486          if (p_derivative)
1487             *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1488          break;
1489       }
1490    case 7:
1491    {
1492       // x is large,
1493       // Compute Q:
1494       result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1495       if (p_derivative)
1496          *p_derivative = result;
1497       result /= x;
1498       if (result != 0)
1499          result *= incomplete_tgamma_large_x(a, x, pol);
1500       break;
1501    }
1502    }
1503 
1504    if(normalised && (result > 1))
1505       result = 1;
1506    if(invert)
1507    {
1508       T gam = normalised ? 1 : boost::math::tgamma(a, pol);
1509       result = gam - result;
1510    }
1511    if(p_derivative)
1512    {
1513       //
1514       // Need to convert prefix term to derivative:
1515       //
1516       if((x < 1) && (tools::max_value<T>() * x < *p_derivative))
1517       {
1518          // overflow, just return an arbitrarily large value:
1519          *p_derivative = tools::max_value<T>() / 2;
1520       }
1521 
1522       *p_derivative /= x;
1523    }
1524 
1525    return result;
1526 }
1527 
1528 //
1529 // Ratios of two gamma functions:
1530 //
1531 template <class T, class Policy, class Lanczos>
1532 T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const Lanczos& l)
1533 {
1534    BOOST_MATH_STD_USING
1535    if(z < tools::epsilon<T>())
1536    {
1537       //
1538       // We get spurious numeric overflow unless we're very careful, this
1539       // can occur either inside Lanczos::lanczos_sum(z) or in the
1540       // final combination of terms, to avoid this, split the product up
1541       // into 2 (or 3) parts:
1542       //
1543       // G(z) / G(L) = 1 / (z * G(L)) ; z < eps, L = z + delta = delta
1544       //    z * G(L) = z * G(lim) * (G(L)/G(lim)) ; lim = largest factorial
1545       //
1546       if(boost::math::max_factorial<T>::value < delta)
1547       {
1548          T ratio = tgamma_delta_ratio_imp_lanczos(delta, T(boost::math::max_factorial<T>::value - delta), pol, l);
1549          ratio *= z;
1550          ratio *= boost::math::unchecked_factorial<T>(boost::math::max_factorial<T>::value - 1);
1551          return 1 / ratio;
1552       }
1553       else
1554       {
1555          return 1 / (z * boost::math::tgamma(z + delta, pol));
1556       }
1557    }
1558    T zgh = static_cast<T>(z + T(Lanczos::g()) - constants::half<T>());
1559    T result;
1560    if(z + delta == z)
1561    {
1562       if (fabs(delta / zgh) < boost::math::tools::epsilon<T>())
1563       {
1564          // We have:
1565          // result = exp((constants::half<T>() - z) * boost::math::log1p(delta / zgh, pol));
1566          // 0.5 - z == -z
1567          // log1p(delta / zgh) = delta / zgh = delta / z
1568          // multiplying we get -delta.
1569          result = exp(-delta);
1570       }
1571       else
1572          // from the pow formula below... but this may actually be wrong, we just can't really calculate it :(
1573          result = 1;
1574    }
1575    else
1576    {
1577       if(fabs(delta) < 10)
1578       {
1579          result = exp((constants::half<T>() - z) * boost::math::log1p(delta / zgh, pol));
1580       }
1581       else
1582       {
1583          result = pow(T(zgh / (zgh + delta)), T(z - constants::half<T>()));
1584       }
1585       // Split the calculation up to avoid spurious overflow:
1586       result *= Lanczos::lanczos_sum(z) / Lanczos::lanczos_sum(T(z + delta));
1587    }
1588    result *= pow(T(constants::e<T>() / (zgh + delta)), delta);
1589    return result;
1590 }
1591 //
1592 // And again without Lanczos support this time:
1593 //
1594 template <class T, class Policy>
1595 T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const lanczos::undefined_lanczos& l)
1596 {
1597    BOOST_MATH_STD_USING
1598 
1599    //
1600    // We adjust z and delta so that both z and z+delta are large enough for
1601    // Sterling's approximation to hold.  We can then calculate the ratio
1602    // for the adjusted values, and rescale back down to z and z+delta.
1603    //
1604    // Get the required shifts first:
1605    //
1606    long numerator_shift = 0;
1607    long denominator_shift = 0;
1608    const int min_z = minimum_argument_for_bernoulli_recursion<T>();
1609 
1610    if (min_z > z)
1611       numerator_shift = 1 + ltrunc(min_z - z);
1612    if (min_z > z + delta)
1613       denominator_shift = 1 + ltrunc(min_z - z - delta);
1614    //
1615    // If the shifts are zero, then we can just combine scaled tgamma's
1616    // and combine the remaining terms:
1617    //
1618    if (numerator_shift == 0 && denominator_shift == 0)
1619    {
1620       T scaled_tgamma_num = scaled_tgamma_no_lanczos(z, pol);
1621       T scaled_tgamma_denom = scaled_tgamma_no_lanczos(T(z + delta), pol);
1622       T result = scaled_tgamma_num / scaled_tgamma_denom;
1623       result *= exp(z * boost::math::log1p(-delta / (z + delta), pol)) * pow(T((delta + z) / constants::e<T>()), -delta);
1624       return result;
1625    }
1626    //
1627    // We're going to have to rescale first, get the adjusted z and delta values,
1628    // plus the ratio for the adjusted values:
1629    //
1630    T zz = z + numerator_shift;
1631    T dd = delta - (numerator_shift - denominator_shift);
1632    T ratio = tgamma_delta_ratio_imp_lanczos(zz, dd, pol, l);
1633    //
1634    // Use gamma recurrence relations to get back to the original
1635    // z and z+delta:
1636    //
1637    for (long long i = 0; i < numerator_shift; ++i)
1638    {
1639       ratio /= (z + i);
1640       if (i < denominator_shift)
1641          ratio *= (z + delta + i);
1642    }
1643    for (long long i = numerator_shift; i < denominator_shift; ++i)
1644    {
1645       ratio *= (z + delta + i);
1646    }
1647    return ratio;
1648 }
1649 
1650 template <class T, class Policy>
1651 T tgamma_delta_ratio_imp(T z, T delta, const Policy& pol)
1652 {
1653    BOOST_MATH_STD_USING
1654 
1655    if((z <= 0) || (z + delta <= 0))
1656    {
1657       // This isn't very sophisticated, or accurate, but it does work:
1658       return boost::math::tgamma(z, pol) / boost::math::tgamma(z + delta, pol);
1659    }
1660 
1661    if(floor(delta) == delta)
1662    {
1663       if(floor(z) == z)
1664       {
1665          //
1666          // Both z and delta are integers, see if we can just use table lookup
1667          // of the factorials to get the result:
1668          //
1669          if((z <= max_factorial<T>::value) && (z + delta <= max_factorial<T>::value))
1670          {
1671             return unchecked_factorial<T>((unsigned)itrunc(z, pol) - 1) / unchecked_factorial<T>((unsigned)itrunc(T(z + delta), pol) - 1);
1672          }
1673       }
1674       if(fabs(delta) < 20)
1675       {
1676          //
1677          // delta is a small integer, we can use a finite product:
1678          //
1679          if(delta == 0)
1680             return 1;
1681          if(delta < 0)
1682          {
1683             z -= 1;
1684             T result = z;
1685             while(0 != (delta += 1))
1686             {
1687                z -= 1;
1688                result *= z;
1689             }
1690             return result;
1691          }
1692          else
1693          {
1694             T result = 1 / z;
1695             while(0 != (delta -= 1))
1696             {
1697                z += 1;
1698                result /= z;
1699             }
1700             return result;
1701          }
1702       }
1703    }
1704    typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1705    return tgamma_delta_ratio_imp_lanczos(z, delta, pol, lanczos_type());
1706 }
1707 
1708 template <class T, class Policy>
1709 T tgamma_ratio_imp(T x, T y, const Policy& pol)
1710 {
1711    BOOST_MATH_STD_USING
1712 
1713    if((x <= 0) || (boost::math::isinf)(x))
1714       return policies::raise_domain_error<T>("boost::math::tgamma_ratio<%1%>(%1%, %1%)", "Gamma function ratios only implemented for positive arguments (got a=%1%).", x, pol);
1715    if((y <= 0) || (boost::math::isinf)(y))
1716       return policies::raise_domain_error<T>("boost::math::tgamma_ratio<%1%>(%1%, %1%)", "Gamma function ratios only implemented for positive arguments (got b=%1%).", y, pol);
1717 
1718    if(x <= tools::min_value<T>())
1719    {
1720       // Special case for denorms...Ugh.
1721       T shift = ldexp(T(1), tools::digits<T>());
1722       return shift * tgamma_ratio_imp(T(x * shift), y, pol);
1723    }
1724 
1725    if((x < max_factorial<T>::value) && (y < max_factorial<T>::value))
1726    {
1727       // Rather than subtracting values, lets just call the gamma functions directly:
1728       return boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
1729    }
1730    T prefix = 1;
1731    if(x < 1)
1732    {
1733       if(y < 2 * max_factorial<T>::value)
1734       {
1735          // We need to sidestep on x as well, otherwise we'll underflow
1736          // before we get to factor in the prefix term:
1737          prefix /= x;
1738          x += 1;
1739          while(y >=  max_factorial<T>::value)
1740          {
1741             y -= 1;
1742             prefix /= y;
1743          }
1744          return prefix * boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
1745       }
1746       //
1747       // result is almost certainly going to underflow to zero, try logs just in case:
1748       //
1749       return exp(boost::math::lgamma(x, pol) - boost::math::lgamma(y, pol));
1750    }
1751    if(y < 1)
1752    {
1753       if(x < 2 * max_factorial<T>::value)
1754       {
1755          // We need to sidestep on y as well, otherwise we'll overflow
1756          // before we get to factor in the prefix term:
1757          prefix *= y;
1758          y += 1;
1759          while(x >= max_factorial<T>::value)
1760          {
1761             x -= 1;
1762             prefix *= x;
1763          }
1764          return prefix * boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
1765       }
1766       //
1767       // Result will almost certainly overflow, try logs just in case:
1768       //
1769       return exp(boost::math::lgamma(x, pol) - boost::math::lgamma(y, pol));
1770    }
1771    //
1772    // Regular case, x and y both large and similar in magnitude:
1773    //
1774    return boost::math::tgamma_delta_ratio(x, y - x, pol);
1775 }
1776 
1777 template <class T, class Policy>
1778 T gamma_p_derivative_imp(T a, T x, const Policy& pol)
1779 {
1780    BOOST_MATH_STD_USING
1781    //
1782    // Usual error checks first:
1783    //
1784    if(a <= 0)
1785       return policies::raise_domain_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
1786    if(x < 0)
1787       return policies::raise_domain_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
1788    //
1789    // Now special cases:
1790    //
1791    if(x == 0)
1792    {
1793       return (a > 1) ? 0 :
1794          (a == 1) ? 1 : policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
1795    }
1796    //
1797    // Normal case:
1798    //
1799    typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1800    T f1 = detail::regularised_gamma_prefix(a, x, pol, lanczos_type());
1801    if((x < 1) && (tools::max_value<T>() * x < f1))
1802    {
1803       // overflow:
1804       return policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
1805    }
1806    if(f1 == 0)
1807    {
1808       // Underflow in calculation, use logs instead:
1809       f1 = a * log(x) - x - lgamma(a, pol) - log(x);
1810       f1 = exp(f1);
1811    }
1812    else
1813       f1 /= x;
1814 
1815    return f1;
1816 }
1817 
1818 template <class T, class Policy>
1819 inline typename tools::promote_args<T>::type
1820    tgamma(T z, const Policy& /* pol */, const std::true_type)
1821 {
1822    BOOST_FPU_EXCEPTION_GUARD
1823    typedef typename tools::promote_args<T>::type result_type;
1824    typedef typename policies::evaluation<result_type, Policy>::type value_type;
1825    typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1826    typedef typename policies::normalise<
1827       Policy,
1828       policies::promote_float<false>,
1829       policies::promote_double<false>,
1830       policies::discrete_quantile<>,
1831       policies::assert_undefined<> >::type forwarding_policy;
1832    return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::gamma_imp(static_cast<value_type>(z), forwarding_policy(), evaluation_type()), "boost::math::tgamma<%1%>(%1%)");
1833 }
1834 
1835 template <class T, class Policy>
1836 struct igamma_initializer
1837 {
1838    struct init
1839    {
1840       init()
1841       {
1842          typedef typename policies::precision<T, Policy>::type precision_type;
1843 
1844          typedef std::integral_constant<int,
1845             precision_type::value <= 0 ? 0 :
1846             precision_type::value <= 53 ? 53 :
1847             precision_type::value <= 64 ? 64 :
1848             precision_type::value <= 113 ? 113 : 0
1849          > tag_type;
1850 
1851          do_init(tag_type());
1852       }
1853       template <int N>
1854       static void do_init(const std::integral_constant<int, N>&)
1855       {
1856          // If std::numeric_limits<T>::digits is zero, we must not call
1857          // our initialization code here as the precision presumably
1858          // varies at runtime, and will not have been set yet.  Plus the
1859          // code requiring initialization isn't called when digits == 0.
1860          if(std::numeric_limits<T>::digits)
1861          {
1862             boost::math::gamma_p(static_cast<T>(400), static_cast<T>(400), Policy());
1863          }
1864       }
1865       static void do_init(const std::integral_constant<int, 53>&){}
1866       void force_instantiate()const{}
1867    };
1868    static const init initializer;
1869    static void force_instantiate()
1870    {
1871       initializer.force_instantiate();
1872    }
1873 };
1874 
1875 template <class T, class Policy>
1876 const typename igamma_initializer<T, Policy>::init igamma_initializer<T, Policy>::initializer;
1877 
1878 template <class T, class Policy>
1879 struct lgamma_initializer
1880 {
1881    struct init
1882    {
1883       init()
1884       {
1885          typedef typename policies::precision<T, Policy>::type precision_type;
1886          typedef std::integral_constant<int,
1887             precision_type::value <= 0 ? 0 :
1888             precision_type::value <= 64 ? 64 :
1889             precision_type::value <= 113 ? 113 : 0
1890          > tag_type;
1891 
1892          do_init(tag_type());
1893       }
1894       static void do_init(const std::integral_constant<int, 64>&)
1895       {
1896          boost::math::lgamma(static_cast<T>(2.5), Policy());
1897          boost::math::lgamma(static_cast<T>(1.25), Policy());
1898          boost::math::lgamma(static_cast<T>(1.75), Policy());
1899       }
1900       static void do_init(const std::integral_constant<int, 113>&)
1901       {
1902          boost::math::lgamma(static_cast<T>(2.5), Policy());
1903          boost::math::lgamma(static_cast<T>(1.25), Policy());
1904          boost::math::lgamma(static_cast<T>(1.5), Policy());
1905          boost::math::lgamma(static_cast<T>(1.75), Policy());
1906       }
1907       static void do_init(const std::integral_constant<int, 0>&)
1908       {
1909       }
1910       void force_instantiate()const{}
1911    };
1912    static const init initializer;
1913    static void force_instantiate()
1914    {
1915       initializer.force_instantiate();
1916    }
1917 };
1918 
1919 template <class T, class Policy>
1920 const typename lgamma_initializer<T, Policy>::init lgamma_initializer<T, Policy>::initializer;
1921 
1922 template <class T1, class T2, class Policy>
1923 inline tools::promote_args_t<T1, T2>
1924    tgamma(T1 a, T2 z, const Policy&, const std::false_type)
1925 {
1926    BOOST_FPU_EXCEPTION_GUARD
1927    typedef tools::promote_args_t<T1, T2> result_type;
1928    typedef typename policies::evaluation<result_type, Policy>::type value_type;
1929    // typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1930    typedef typename policies::normalise<
1931       Policy,
1932       policies::promote_float<false>,
1933       policies::promote_double<false>,
1934       policies::discrete_quantile<>,
1935       policies::assert_undefined<> >::type forwarding_policy;
1936 
1937    igamma_initializer<value_type, forwarding_policy>::force_instantiate();
1938 
1939    return policies::checked_narrowing_cast<result_type, forwarding_policy>(
1940       detail::gamma_incomplete_imp(static_cast<value_type>(a),
1941       static_cast<value_type>(z), false, true,
1942       forwarding_policy(), static_cast<value_type*>(nullptr)), "boost::math::tgamma<%1%>(%1%, %1%)");
1943 }
1944 
1945 template <class T1, class T2>
1946 inline tools::promote_args_t<T1, T2>
1947    tgamma(T1 a, T2 z, const std::false_type& tag)
1948 {
1949    return tgamma(a, z, policies::policy<>(), tag);
1950 }
1951 
1952 
1953 } // namespace detail
1954 
1955 template <class T>
1956 inline typename tools::promote_args<T>::type
1957    tgamma(T z)
1958 {
1959    return tgamma(z, policies::policy<>());
1960 }
1961 
1962 template <class T, class Policy>
1963 inline typename tools::promote_args<T>::type
1964    lgamma(T z, int* sign, const Policy&)
1965 {
1966    BOOST_FPU_EXCEPTION_GUARD
1967    typedef typename tools::promote_args<T>::type result_type;
1968    typedef typename policies::evaluation<result_type, Policy>::type value_type;
1969    typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1970    typedef typename policies::normalise<
1971       Policy,
1972       policies::promote_float<false>,
1973       policies::promote_double<false>,
1974       policies::discrete_quantile<>,
1975       policies::assert_undefined<> >::type forwarding_policy;
1976 
1977    detail::lgamma_initializer<value_type, forwarding_policy>::force_instantiate();
1978 
1979    return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::lgamma_imp(static_cast<value_type>(z), forwarding_policy(), evaluation_type(), sign), "boost::math::lgamma<%1%>(%1%)");
1980 }
1981 
1982 template <class T>
1983 inline typename tools::promote_args<T>::type
1984    lgamma(T z, int* sign)
1985 {
1986    return lgamma(z, sign, policies::policy<>());
1987 }
1988 
1989 template <class T, class Policy>
1990 inline typename tools::promote_args<T>::type
1991    lgamma(T x, const Policy& pol)
1992 {
1993    return ::boost::math::lgamma(x, nullptr, pol);
1994 }
1995 
1996 template <class T>
1997 inline typename tools::promote_args<T>::type
1998    lgamma(T x)
1999 {
2000    return ::boost::math::lgamma(x, nullptr, policies::policy<>());
2001 }
2002 
2003 template <class T, class Policy>
2004 inline typename tools::promote_args<T>::type
2005    tgamma1pm1(T z, const Policy& /* pol */)
2006 {
2007    BOOST_FPU_EXCEPTION_GUARD
2008    typedef typename tools::promote_args<T>::type result_type;
2009    typedef typename policies::evaluation<result_type, Policy>::type value_type;
2010    typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2011    typedef typename policies::normalise<
2012       Policy,
2013       policies::promote_float<false>,
2014       policies::promote_double<false>,
2015       policies::discrete_quantile<>,
2016       policies::assert_undefined<> >::type forwarding_policy;
2017 
2018    return policies::checked_narrowing_cast<typename std::remove_cv<result_type>::type, forwarding_policy>(detail::tgammap1m1_imp(static_cast<value_type>(z), forwarding_policy(), evaluation_type()), "boost::math::tgamma1pm1<%!%>(%1%)");
2019 }
2020 
2021 template <class T>
2022 inline typename tools::promote_args<T>::type
2023    tgamma1pm1(T z)
2024 {
2025    return tgamma1pm1(z, policies::policy<>());
2026 }
2027 
2028 //
2029 // Full upper incomplete gamma:
2030 //
2031 template <class T1, class T2>
2032 inline tools::promote_args_t<T1, T2>
2033    tgamma(T1 a, T2 z)
2034 {
2035    //
2036    // Type T2 could be a policy object, or a value, select the
2037    // right overload based on T2:
2038    //
2039    using maybe_policy = typename policies::is_policy<T2>::type;
2040    using result_type = tools::promote_args_t<T1, T2>;
2041    return static_cast<result_type>(detail::tgamma(a, z, maybe_policy()));
2042 }
2043 template <class T1, class T2, class Policy>
2044 inline tools::promote_args_t<T1, T2>
2045    tgamma(T1 a, T2 z, const Policy& pol)
2046 {
2047    using result_type = tools::promote_args_t<T1, T2>;
2048    return static_cast<result_type>(detail::tgamma(a, z, pol, std::false_type()));
2049 }
2050 //
2051 // Full lower incomplete gamma:
2052 //
2053 template <class T1, class T2, class Policy>
2054 inline tools::promote_args_t<T1, T2>
2055    tgamma_lower(T1 a, T2 z, const Policy&)
2056 {
2057    BOOST_FPU_EXCEPTION_GUARD
2058    typedef tools::promote_args_t<T1, T2> result_type;
2059    typedef typename policies::evaluation<result_type, Policy>::type value_type;
2060    // typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2061    typedef typename policies::normalise<
2062       Policy,
2063       policies::promote_float<false>,
2064       policies::promote_double<false>,
2065       policies::discrete_quantile<>,
2066       policies::assert_undefined<> >::type forwarding_policy;
2067 
2068    detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2069 
2070    return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2071       detail::gamma_incomplete_imp(static_cast<value_type>(a),
2072       static_cast<value_type>(z), false, false,
2073       forwarding_policy(), static_cast<value_type*>(nullptr)), "tgamma_lower<%1%>(%1%, %1%)");
2074 }
2075 template <class T1, class T2>
2076 inline tools::promote_args_t<T1, T2>
2077    tgamma_lower(T1 a, T2 z)
2078 {
2079    return tgamma_lower(a, z, policies::policy<>());
2080 }
2081 //
2082 // Regularised upper incomplete gamma:
2083 //
2084 template <class T1, class T2, class Policy>
2085 inline tools::promote_args_t<T1, T2>
2086    gamma_q(T1 a, T2 z, const Policy& /* pol */)
2087 {
2088    BOOST_FPU_EXCEPTION_GUARD
2089    typedef tools::promote_args_t<T1, T2> result_type;
2090    typedef typename policies::evaluation<result_type, Policy>::type value_type;
2091    // typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2092    typedef typename policies::normalise<
2093       Policy,
2094       policies::promote_float<false>,
2095       policies::promote_double<false>,
2096       policies::discrete_quantile<>,
2097       policies::assert_undefined<> >::type forwarding_policy;
2098 
2099    detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2100 
2101    return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2102       detail::gamma_incomplete_imp(static_cast<value_type>(a),
2103       static_cast<value_type>(z), true, true,
2104       forwarding_policy(), static_cast<value_type*>(nullptr)), "gamma_q<%1%>(%1%, %1%)");
2105 }
2106 template <class T1, class T2>
2107 inline tools::promote_args_t<T1, T2>
2108    gamma_q(T1 a, T2 z)
2109 {
2110    return gamma_q(a, z, policies::policy<>());
2111 }
2112 //
2113 // Regularised lower incomplete gamma:
2114 //
2115 template <class T1, class T2, class Policy>
2116 inline tools::promote_args_t<T1, T2>
2117    gamma_p(T1 a, T2 z, const Policy&)
2118 {
2119    BOOST_FPU_EXCEPTION_GUARD
2120    typedef tools::promote_args_t<T1, T2> result_type;
2121    typedef typename policies::evaluation<result_type, Policy>::type value_type;
2122    // typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2123    typedef typename policies::normalise<
2124       Policy,
2125       policies::promote_float<false>,
2126       policies::promote_double<false>,
2127       policies::discrete_quantile<>,
2128       policies::assert_undefined<> >::type forwarding_policy;
2129 
2130    detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2131 
2132    return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2133       detail::gamma_incomplete_imp(static_cast<value_type>(a),
2134       static_cast<value_type>(z), true, false,
2135       forwarding_policy(), static_cast<value_type*>(nullptr)), "gamma_p<%1%>(%1%, %1%)");
2136 }
2137 template <class T1, class T2>
2138 inline tools::promote_args_t<T1, T2>
2139    gamma_p(T1 a, T2 z)
2140 {
2141    return gamma_p(a, z, policies::policy<>());
2142 }
2143 
2144 // ratios of gamma functions:
2145 template <class T1, class T2, class Policy>
2146 inline tools::promote_args_t<T1, T2>
2147    tgamma_delta_ratio(T1 z, T2 delta, const Policy& /* pol */)
2148 {
2149    BOOST_FPU_EXCEPTION_GUARD
2150    typedef tools::promote_args_t<T1, T2> result_type;
2151    typedef typename policies::evaluation<result_type, Policy>::type value_type;
2152    typedef typename policies::normalise<
2153       Policy,
2154       policies::promote_float<false>,
2155       policies::promote_double<false>,
2156       policies::discrete_quantile<>,
2157       policies::assert_undefined<> >::type forwarding_policy;
2158 
2159    return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::tgamma_delta_ratio_imp(static_cast<value_type>(z), static_cast<value_type>(delta), forwarding_policy()), "boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)");
2160 }
2161 template <class T1, class T2>
2162 inline tools::promote_args_t<T1, T2>
2163    tgamma_delta_ratio(T1 z, T2 delta)
2164 {
2165    return tgamma_delta_ratio(z, delta, policies::policy<>());
2166 }
2167 template <class T1, class T2, class Policy>
2168 inline tools::promote_args_t<T1, T2>
2169    tgamma_ratio(T1 a, T2 b, const Policy&)
2170 {
2171    typedef tools::promote_args_t<T1, T2> result_type;
2172    typedef typename policies::evaluation<result_type, Policy>::type value_type;
2173    typedef typename policies::normalise<
2174       Policy,
2175       policies::promote_float<false>,
2176       policies::promote_double<false>,
2177       policies::discrete_quantile<>,
2178       policies::assert_undefined<> >::type forwarding_policy;
2179 
2180    return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::tgamma_ratio_imp(static_cast<value_type>(a), static_cast<value_type>(b), forwarding_policy()), "boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)");
2181 }
2182 template <class T1, class T2>
2183 inline tools::promote_args_t<T1, T2>
2184    tgamma_ratio(T1 a, T2 b)
2185 {
2186    return tgamma_ratio(a, b, policies::policy<>());
2187 }
2188 
2189 template <class T1, class T2, class Policy>
2190 inline tools::promote_args_t<T1, T2>
2191    gamma_p_derivative(T1 a, T2 x, const Policy&)
2192 {
2193    BOOST_FPU_EXCEPTION_GUARD
2194    typedef tools::promote_args_t<T1, T2> result_type;
2195    typedef typename policies::evaluation<result_type, Policy>::type value_type;
2196    typedef typename policies::normalise<
2197       Policy,
2198       policies::promote_float<false>,
2199       policies::promote_double<false>,
2200       policies::discrete_quantile<>,
2201       policies::assert_undefined<> >::type forwarding_policy;
2202 
2203    return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::gamma_p_derivative_imp(static_cast<value_type>(a), static_cast<value_type>(x), forwarding_policy()), "boost::math::gamma_p_derivative<%1%>(%1%, %1%)");
2204 }
2205 template <class T1, class T2>
2206 inline tools::promote_args_t<T1, T2>
2207    gamma_p_derivative(T1 a, T2 x)
2208 {
2209    return gamma_p_derivative(a, x, policies::policy<>());
2210 }
2211 
2212 } // namespace math
2213 } // namespace boost
2214 
2215 #ifdef _MSC_VER
2216 # pragma warning(pop)
2217 #endif
2218 
2219 #include <boost/math/special_functions/detail/igamma_inverse.hpp>
2220 #include <boost/math/special_functions/detail/gamma_inva.hpp>
2221 #include <boost/math/special_functions/erf.hpp>
2222 
2223 #endif // BOOST_MATH_SF_GAMMA_HPP