File indexing completed on 2025-01-18 09:40:14
0001
0002
0003
0004
0005
0006
0007
0008
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)
0045 # pragma warning(disable: 4127)
0046 # pragma warning(disable: 4100)
0047 # pragma warning(disable: 6326)
0048
0049
0050
0051
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
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
0082
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 }
0107
0108
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
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
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
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
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
0262 result = log(gamma_imp(z, pol, l));
0263 }
0264 else
0265 {
0266
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
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
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
0311
0312
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
0339
0340
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
0351
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
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
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
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
0404
0405
0406
0407 BOOST_MATH_ASSERT(minimum_argument_for_bernoulli_recursion<T>() <= z);
0408
0409
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
0431
0432
0433
0434
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
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
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
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
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
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
0482 T zz((!b_neg) ? z : -z);
0483
0484
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
0498
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
0529 if(n_recur)
0530 {
0531
0532
0533
0534
0535
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
0546 if(b_neg)
0547 {
0548
0549
0550
0551
0552
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
0584
0585
0586
0587 BOOST_MATH_STD_USING
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
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
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
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
0647
0648
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
0662
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
0670
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
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
0691
0692
0693
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
0720
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
0741 result = boost::math::tgamma(1+dz, pol) - 1;
0742 BOOST_MATH_INSTRUMENT_CODE(result);
0743 }
0744 else
0745 {
0746
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
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
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
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
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
0809
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 T prefix;
0817 if (z > tools::max_value<T>())
0818 return 0;
0819 T alz = a * log(z);
0820
0821 if(z >= 1)
0822 {
0823 if((alz < tools::log_max_value<T>()) && (-z > tools::log_min_value<T>()))
0824 {
0825 prefix = pow(z, a) * exp(-z);
0826 }
0827 else if(a >= 1)
0828 {
0829 prefix = pow(T(z / exp(z/a)), a);
0830 }
0831 else
0832 {
0833 prefix = exp(alz - z);
0834 }
0835 }
0836 else
0837 {
0838 if(alz > tools::log_min_value<T>())
0839 {
0840 prefix = pow(z, a) * exp(-z);
0841 }
0842 else if(z/a < tools::log_max_value<T>())
0843 {
0844 prefix = pow(T(z / exp(z/a)), a);
0845 }
0846 else
0847 {
0848 prefix = exp(alz - z);
0849 }
0850 }
0851
0852
0853
0854
0855 if((boost::math::fpclassify)(prefix) == (int)FP_INFINITE)
0856 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);
0857
0858 return prefix;
0859 }
0860
0861
0862
0863
0864 template <class T, class Policy, class Lanczos>
0865 T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l)
0866 {
0867 BOOST_MATH_STD_USING
0868 if (z >= tools::max_value<T>())
0869 return 0;
0870 T agh = a + static_cast<T>(Lanczos::g()) - T(0.5);
0871 T prefix;
0872 T d = ((z - a) - static_cast<T>(Lanczos::g()) + T(0.5)) / agh;
0873
0874 if(a < 1)
0875 {
0876
0877
0878
0879
0880
0881
0882
0883
0884
0885 if((z <= tools::log_min_value<T>()) || (a < 1 / tools::max_value<T>()))
0886 {
0887
0888 return exp(a * log(z) - z - lgamma_imp(a, pol, l));
0889 }
0890 else
0891 {
0892
0893
0894 return pow(z, a) * exp(-z) / gamma_imp(a, pol, l);
0895 }
0896 }
0897 else if((fabs(d*d*a) <= 100) && (a > 150))
0898 {
0899
0900 prefix = a * boost::math::log1pmx(d, pol) + z * static_cast<T>(0.5 - Lanczos::g()) / agh;
0901 prefix = exp(prefix);
0902 }
0903 else
0904 {
0905
0906
0907
0908
0909
0910 T alz = a * log(z / agh);
0911 T amz = a - z;
0912 if(((std::min)(alz, amz) <= tools::log_min_value<T>()) || ((std::max)(alz, amz) >= tools::log_max_value<T>()))
0913 {
0914 T amza = amz / a;
0915 if(((std::min)(alz, amz)/2 > tools::log_min_value<T>()) && ((std::max)(alz, amz)/2 < tools::log_max_value<T>()))
0916 {
0917
0918 T sq = pow(z / agh, a / 2) * exp(amz / 2);
0919 prefix = sq * sq;
0920 }
0921 else if(((std::min)(alz, amz)/4 > tools::log_min_value<T>()) && ((std::max)(alz, amz)/4 < tools::log_max_value<T>()) && (z > a))
0922 {
0923
0924 T sq = pow(z / agh, a / 4) * exp(amz / 4);
0925 prefix = sq * sq;
0926 prefix *= prefix;
0927 }
0928 else if((amza > tools::log_min_value<T>()) && (amza < tools::log_max_value<T>()))
0929 {
0930 prefix = pow(T((z * exp(amza)) / agh), a);
0931 }
0932 else
0933 {
0934 prefix = exp(alz + amz);
0935 }
0936 }
0937 else
0938 {
0939 prefix = pow(T(z / agh), a) * exp(amz);
0940 }
0941 }
0942 prefix *= sqrt(agh / boost::math::constants::e<T>()) / Lanczos::lanczos_sum_expG_scaled(a);
0943 return prefix;
0944 }
0945
0946
0947
0948 template <class T, class Policy>
0949 T regularised_gamma_prefix(T a, T z, const Policy& pol, const lanczos::undefined_lanczos& l)
0950 {
0951 BOOST_MATH_STD_USING
0952
0953 if((a < 1) && (z < 1))
0954 {
0955
0956 return pow(z, a) * exp(-z) / boost::math::tgamma(a, pol);
0957 }
0958 else if(a > minimum_argument_for_bernoulli_recursion<T>())
0959 {
0960 T scaled_gamma = scaled_tgamma_no_lanczos(a, pol);
0961 T power_term = pow(z / a, a / 2);
0962 T a_minus_z = a - z;
0963 if ((0 == power_term) || (fabs(a_minus_z) > tools::log_max_value<T>()))
0964 {
0965
0966 return exp(a * log(z / a) + a_minus_z - log(scaled_gamma));
0967 }
0968 return (power_term * exp(a_minus_z)) * (power_term / scaled_gamma);
0969 }
0970 else
0971 {
0972
0973
0974
0975
0976 const int min_z = minimum_argument_for_bernoulli_recursion<T>();
0977 long shift = 1 + ltrunc(min_z - a);
0978 T result = regularised_gamma_prefix(T(a + shift), z, pol, l);
0979 if (result != 0)
0980 {
0981 for (long i = 0; i < shift; ++i)
0982 {
0983 result /= z;
0984 result *= a + i;
0985 }
0986 return result;
0987 }
0988 else
0989 {
0990
0991
0992
0993
0994
0995 T scaled_gamma = scaled_tgamma_no_lanczos(T(a + shift), pol);
0996 T power_term_1 = pow(T(z / (a + shift)), a);
0997 T power_term_2 = pow(T(a + shift), T(-shift));
0998 T power_term_3 = exp(a + shift - z);
0999 if ((0 == power_term_1) || (0 == power_term_2) || (0 == power_term_3) || (fabs(a + shift - z) > tools::log_max_value<T>()))
1000 {
1001
1002
1003 return exp(a * log(z) - z - boost::math::lgamma(a, pol));
1004 }
1005 result = power_term_1 * power_term_2 * power_term_3 / scaled_gamma;
1006 for (long i = 0; i < shift; ++i)
1007 {
1008 result *= a + i;
1009 }
1010 return result;
1011 }
1012 }
1013 }
1014
1015
1016
1017 template <class T, class Policy>
1018 inline T tgamma_small_upper_part(T a, T x, const Policy& pol, T* pgam = 0, bool invert = false, T* pderivative = 0)
1019 {
1020 BOOST_MATH_STD_USING
1021
1022
1023
1024 T result;
1025 result = boost::math::tgamma1pm1(a, pol);
1026 if(pgam)
1027 *pgam = (result + 1) / a;
1028 T p = boost::math::powm1(x, a, pol);
1029 result -= p;
1030 result /= a;
1031 detail::small_gamma2_series<T> s(a, x);
1032 std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>() - 10;
1033 p += 1;
1034 if(pderivative)
1035 *pderivative = p / (*pgam * exp(x));
1036 T init_value = invert ? *pgam : 0;
1037 result = -p * tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, (init_value - result) / p);
1038 policies::check_series_iterations<T>("boost::math::tgamma_small_upper_part<%1%>(%1%, %1%)", max_iter, pol);
1039 if(invert)
1040 result = -result;
1041 return result;
1042 }
1043
1044
1045
1046 template <class T, class Policy>
1047 inline T finite_gamma_q(T a, T x, Policy const& pol, T* pderivative = 0)
1048 {
1049
1050
1051
1052 BOOST_MATH_STD_USING
1053 T e = exp(-x);
1054 T sum = e;
1055 if(sum != 0)
1056 {
1057 T term = sum;
1058 for(unsigned n = 1; n < a; ++n)
1059 {
1060 term /= n;
1061 term *= x;
1062 sum += term;
1063 }
1064 }
1065 if(pderivative)
1066 {
1067 *pderivative = e * pow(x, a) / boost::math::unchecked_factorial<T>(itrunc(T(a - 1), pol));
1068 }
1069 return sum;
1070 }
1071
1072
1073
1074 template <class T, class Policy>
1075 T finite_half_gamma_q(T a, T x, T* p_derivative, const Policy& pol)
1076 {
1077
1078
1079
1080 BOOST_MATH_STD_USING
1081 T e = boost::math::erfc(sqrt(x), pol);
1082 if((e != 0) && (a > 1))
1083 {
1084 T term = exp(-x) / sqrt(constants::pi<T>() * x);
1085 term *= x;
1086 static const T half = T(1) / 2;
1087 term /= half;
1088 T sum = term;
1089 for(unsigned n = 2; n < a; ++n)
1090 {
1091 term /= n - half;
1092 term *= x;
1093 sum += term;
1094 }
1095 e += sum;
1096 if(p_derivative)
1097 {
1098 *p_derivative = 0;
1099 }
1100 }
1101 else if(p_derivative)
1102 {
1103
1104 *p_derivative = sqrt(x) * exp(-x) / constants::root_pi<T>();
1105 }
1106 return e;
1107 }
1108
1109
1110
1111 template <class T>
1112 struct incomplete_tgamma_large_x_series
1113 {
1114 typedef T result_type;
1115 incomplete_tgamma_large_x_series(const T& a, const T& x)
1116 : a_poch(a - 1), z(x), term(1) {}
1117 T operator()()
1118 {
1119 T result = term;
1120 term *= a_poch / z;
1121 a_poch -= 1;
1122 return result;
1123 }
1124 T a_poch, z, term;
1125 };
1126
1127 template <class T, class Policy>
1128 T incomplete_tgamma_large_x(const T& a, const T& x, const Policy& pol)
1129 {
1130 BOOST_MATH_STD_USING
1131 incomplete_tgamma_large_x_series<T> s(a, x);
1132 std::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
1133 T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
1134 boost::math::policies::check_series_iterations<T>("boost::math::tgamma<%1%>(%1%,%1%)", max_iter, pol);
1135 return result;
1136 }
1137
1138
1139
1140
1141
1142 template <class T, class Policy>
1143 T gamma_incomplete_imp(T a, T x, bool normalised, bool invert,
1144 const Policy& pol, T* p_derivative)
1145 {
1146 static const char* function = "boost::math::gamma_p<%1%>(%1%, %1%)";
1147 if(a <= 0)
1148 return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
1149 if(x < 0)
1150 return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
1151
1152 BOOST_MATH_STD_USING
1153
1154 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1155
1156 T result = 0;
1157
1158 if(a >= max_factorial<T>::value && !normalised)
1159 {
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170 if(invert && (a * 4 < x))
1171 {
1172
1173 result = a * log(x) - x;
1174 if(p_derivative)
1175 *p_derivative = exp(result);
1176 result += log(upper_gamma_fraction(a, x, policies::get_epsilon<T, Policy>()));
1177 }
1178 else if(!invert && (a > 4 * x))
1179 {
1180
1181 result = a * log(x) - x;
1182 if(p_derivative)
1183 *p_derivative = exp(result);
1184 T init_value = 0;
1185 result += log(detail::lower_gamma_series(a, x, pol, init_value) / a);
1186 }
1187 else
1188 {
1189 result = gamma_incomplete_imp(a, x, true, invert, pol, p_derivative);
1190 if(result == 0)
1191 {
1192 if(invert)
1193 {
1194
1195 result = 1 + 1 / (12 * a) + 1 / (288 * a * a);
1196 result = log(result) - a + (a - 0.5f) * log(a) + log(boost::math::constants::root_two_pi<T>());
1197 if(p_derivative)
1198 *p_derivative = exp(a * log(x) - x);
1199 }
1200 else
1201 {
1202
1203
1204
1205 result = a * log(x) - x;
1206 if(p_derivative)
1207 *p_derivative = exp(result);
1208 T init_value = 0;
1209 result += log(detail::lower_gamma_series(a, x, pol, init_value) / a);
1210 }
1211 }
1212 else
1213 {
1214 result = log(result) + boost::math::lgamma(a, pol);
1215 }
1216 }
1217 if(result > tools::log_max_value<T>())
1218 return policies::raise_overflow_error<T>(function, nullptr, pol);
1219 return exp(result);
1220 }
1221
1222 BOOST_MATH_ASSERT((p_derivative == nullptr) || normalised);
1223
1224 bool is_int, is_half_int;
1225 bool is_small_a = (a < 30) && (a <= x + 1) && (x < tools::log_max_value<T>());
1226 if(is_small_a)
1227 {
1228 T fa = floor(a);
1229 is_int = (fa == a);
1230 is_half_int = is_int ? false : (fabs(fa - a) == 0.5f);
1231 }
1232 else
1233 {
1234 is_int = is_half_int = false;
1235 }
1236
1237 int eval_method;
1238
1239 if(is_int && (x > 0.6))
1240 {
1241
1242 invert = !invert;
1243 eval_method = 0;
1244 }
1245 else if(is_half_int && (x > 0.2))
1246 {
1247
1248 invert = !invert;
1249 eval_method = 1;
1250 }
1251 else if((x < tools::root_epsilon<T>()) && (a > 1))
1252 {
1253 eval_method = 6;
1254 }
1255 else if ((x > 1000) && ((a < x) || (fabs(a - 50) / x < 1)))
1256 {
1257
1258 invert = !invert;
1259 eval_method = 7;
1260 }
1261 else if(x < T(0.5))
1262 {
1263
1264
1265
1266 if(T(-0.4) / log(x) < a)
1267 {
1268 eval_method = 2;
1269 }
1270 else
1271 {
1272 eval_method = 3;
1273 }
1274 }
1275 else if(x < T(1.1))
1276 {
1277
1278
1279
1280 if(x * 0.75f < a)
1281 {
1282 eval_method = 2;
1283 }
1284 else
1285 {
1286 eval_method = 3;
1287 }
1288 }
1289 else
1290 {
1291
1292
1293
1294
1295
1296 bool use_temme = false;
1297 if(normalised && std::numeric_limits<T>::is_specialized && (a > 20))
1298 {
1299 T sigma = fabs((x-a)/a);
1300 if((a > 200) && (policies::digits<T, Policy>() <= 113))
1301 {
1302
1303
1304
1305
1306
1307
1308
1309
1310 if(20 / a > sigma * sigma)
1311 use_temme = true;
1312 }
1313 else if(policies::digits<T, Policy>() <= 64)
1314 {
1315
1316
1317
1318 if(sigma < 0.4)
1319 use_temme = true;
1320 }
1321 }
1322 if(use_temme)
1323 {
1324 eval_method = 5;
1325 }
1326 else
1327 {
1328
1329
1330
1331
1332
1333
1334
1335
1336 if(x - (1 / (3 * x)) < a)
1337 {
1338 eval_method = 2;
1339 }
1340 else
1341 {
1342 eval_method = 4;
1343 invert = !invert;
1344 }
1345 }
1346 }
1347
1348 switch(eval_method)
1349 {
1350 case 0:
1351 {
1352 result = finite_gamma_q(a, x, pol, p_derivative);
1353 if(!normalised)
1354 result *= boost::math::tgamma(a, pol);
1355 break;
1356 }
1357 case 1:
1358 {
1359 result = finite_half_gamma_q(a, x, p_derivative, pol);
1360 if(!normalised)
1361 result *= boost::math::tgamma(a, pol);
1362 if(p_derivative && (*p_derivative == 0))
1363 *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1364 break;
1365 }
1366 case 2:
1367 {
1368
1369 result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1370 if(p_derivative)
1371 *p_derivative = result;
1372 if(result != 0)
1373 {
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386 T init_value = 0;
1387 bool optimised_invert = false;
1388 if(invert)
1389 {
1390 init_value = (normalised ? 1 : boost::math::tgamma(a, pol));
1391 if(normalised || (result >= 1) || (tools::max_value<T>() * result > init_value))
1392 {
1393 init_value /= result;
1394 if(normalised || (a < 1) || (tools::max_value<T>() / a > init_value))
1395 {
1396 init_value *= -a;
1397 optimised_invert = true;
1398 }
1399 else
1400 init_value = 0;
1401 }
1402 else
1403 init_value = 0;
1404 }
1405 result *= detail::lower_gamma_series(a, x, pol, init_value) / a;
1406 if(optimised_invert)
1407 {
1408 invert = false;
1409 result = -result;
1410 }
1411 }
1412 break;
1413 }
1414 case 3:
1415 {
1416
1417 invert = !invert;
1418 T g;
1419 result = tgamma_small_upper_part(a, x, pol, &g, invert, p_derivative);
1420 invert = false;
1421 if(normalised)
1422 result /= g;
1423 break;
1424 }
1425 case 4:
1426 {
1427
1428 result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1429 if(p_derivative)
1430 *p_derivative = result;
1431 if(result != 0)
1432 result *= upper_gamma_fraction(a, x, policies::get_epsilon<T, Policy>());
1433 break;
1434 }
1435 case 5:
1436 {
1437
1438
1439
1440
1441
1442
1443
1444
1445 typedef typename policies::precision<T, Policy>::type precision_type;
1446
1447 typedef std::integral_constant<int,
1448 precision_type::value <= 0 ? 0 :
1449 precision_type::value <= 53 ? 53 :
1450 precision_type::value <= 64 ? 64 :
1451 precision_type::value <= 113 ? 113 : 0
1452 > tag_type;
1453
1454 result = igamma_temme_large(a, x, pol, static_cast<tag_type const*>(nullptr));
1455 if(x >= a)
1456 invert = !invert;
1457 if(p_derivative)
1458 *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1459 break;
1460 }
1461 case 6:
1462 {
1463
1464
1465 if(!normalised)
1466 result = pow(x, a) / (a);
1467 else
1468 {
1469 #ifndef BOOST_NO_EXCEPTIONS
1470 try
1471 {
1472 #endif
1473 result = pow(x, a) / boost::math::tgamma(a + 1, pol);
1474 #ifndef BOOST_NO_EXCEPTIONS
1475 }
1476 catch (const std::overflow_error&)
1477 {
1478 result = 0;
1479 }
1480 #endif
1481 }
1482 result *= 1 - a * x / (a + 1);
1483 if (p_derivative)
1484 *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1485 break;
1486 }
1487 case 7:
1488 {
1489
1490
1491 result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1492 if (p_derivative)
1493 *p_derivative = result;
1494 result /= x;
1495 if (result != 0)
1496 result *= incomplete_tgamma_large_x(a, x, pol);
1497 break;
1498 }
1499 }
1500
1501 if(normalised && (result > 1))
1502 result = 1;
1503 if(invert)
1504 {
1505 T gam = normalised ? 1 : boost::math::tgamma(a, pol);
1506 result = gam - result;
1507 }
1508 if(p_derivative)
1509 {
1510
1511
1512
1513 if((x < 1) && (tools::max_value<T>() * x < *p_derivative))
1514 {
1515
1516 *p_derivative = tools::max_value<T>() / 2;
1517 }
1518
1519 *p_derivative /= x;
1520 }
1521
1522 return result;
1523 }
1524
1525
1526
1527
1528 template <class T, class Policy, class Lanczos>
1529 T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const Lanczos& l)
1530 {
1531 BOOST_MATH_STD_USING
1532 if(z < tools::epsilon<T>())
1533 {
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543 if(boost::math::max_factorial<T>::value < delta)
1544 {
1545 T ratio = tgamma_delta_ratio_imp_lanczos(delta, T(boost::math::max_factorial<T>::value - delta), pol, l);
1546 ratio *= z;
1547 ratio *= boost::math::unchecked_factorial<T>(boost::math::max_factorial<T>::value - 1);
1548 return 1 / ratio;
1549 }
1550 else
1551 {
1552 return 1 / (z * boost::math::tgamma(z + delta, pol));
1553 }
1554 }
1555 T zgh = static_cast<T>(z + T(Lanczos::g()) - constants::half<T>());
1556 T result;
1557 if(z + delta == z)
1558 {
1559 if (fabs(delta / zgh) < boost::math::tools::epsilon<T>())
1560 {
1561
1562
1563
1564
1565
1566 result = exp(-delta);
1567 }
1568 else
1569
1570 result = 1;
1571 }
1572 else
1573 {
1574 if(fabs(delta) < 10)
1575 {
1576 result = exp((constants::half<T>() - z) * boost::math::log1p(delta / zgh, pol));
1577 }
1578 else
1579 {
1580 result = pow(T(zgh / (zgh + delta)), T(z - constants::half<T>()));
1581 }
1582
1583 result *= Lanczos::lanczos_sum(z) / Lanczos::lanczos_sum(T(z + delta));
1584 }
1585 result *= pow(T(constants::e<T>() / (zgh + delta)), delta);
1586 return result;
1587 }
1588
1589
1590
1591 template <class T, class Policy>
1592 T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const lanczos::undefined_lanczos& l)
1593 {
1594 BOOST_MATH_STD_USING
1595
1596
1597
1598
1599
1600
1601
1602
1603 long numerator_shift = 0;
1604 long denominator_shift = 0;
1605 const int min_z = minimum_argument_for_bernoulli_recursion<T>();
1606
1607 if (min_z > z)
1608 numerator_shift = 1 + ltrunc(min_z - z);
1609 if (min_z > z + delta)
1610 denominator_shift = 1 + ltrunc(min_z - z - delta);
1611
1612
1613
1614
1615 if (numerator_shift == 0 && denominator_shift == 0)
1616 {
1617 T scaled_tgamma_num = scaled_tgamma_no_lanczos(z, pol);
1618 T scaled_tgamma_denom = scaled_tgamma_no_lanczos(T(z + delta), pol);
1619 T result = scaled_tgamma_num / scaled_tgamma_denom;
1620 result *= exp(z * boost::math::log1p(-delta / (z + delta), pol)) * pow(T((delta + z) / constants::e<T>()), -delta);
1621 return result;
1622 }
1623
1624
1625
1626
1627 T zz = z + numerator_shift;
1628 T dd = delta - (numerator_shift - denominator_shift);
1629 T ratio = tgamma_delta_ratio_imp_lanczos(zz, dd, pol, l);
1630
1631
1632
1633
1634 for (long long i = 0; i < numerator_shift; ++i)
1635 {
1636 ratio /= (z + i);
1637 if (i < denominator_shift)
1638 ratio *= (z + delta + i);
1639 }
1640 for (long long i = numerator_shift; i < denominator_shift; ++i)
1641 {
1642 ratio *= (z + delta + i);
1643 }
1644 return ratio;
1645 }
1646
1647 template <class T, class Policy>
1648 T tgamma_delta_ratio_imp(T z, T delta, const Policy& pol)
1649 {
1650 BOOST_MATH_STD_USING
1651
1652 if((z <= 0) || (z + delta <= 0))
1653 {
1654
1655 return boost::math::tgamma(z, pol) / boost::math::tgamma(z + delta, pol);
1656 }
1657
1658 if(floor(delta) == delta)
1659 {
1660 if(floor(z) == z)
1661 {
1662
1663
1664
1665
1666 if((z <= max_factorial<T>::value) && (z + delta <= max_factorial<T>::value))
1667 {
1668 return unchecked_factorial<T>((unsigned)itrunc(z, pol) - 1) / unchecked_factorial<T>((unsigned)itrunc(T(z + delta), pol) - 1);
1669 }
1670 }
1671 if(fabs(delta) < 20)
1672 {
1673
1674
1675
1676 if(delta == 0)
1677 return 1;
1678 if(delta < 0)
1679 {
1680 z -= 1;
1681 T result = z;
1682 while(0 != (delta += 1))
1683 {
1684 z -= 1;
1685 result *= z;
1686 }
1687 return result;
1688 }
1689 else
1690 {
1691 T result = 1 / z;
1692 while(0 != (delta -= 1))
1693 {
1694 z += 1;
1695 result /= z;
1696 }
1697 return result;
1698 }
1699 }
1700 }
1701 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1702 return tgamma_delta_ratio_imp_lanczos(z, delta, pol, lanczos_type());
1703 }
1704
1705 template <class T, class Policy>
1706 T tgamma_ratio_imp(T x, T y, const Policy& pol)
1707 {
1708 BOOST_MATH_STD_USING
1709
1710 if((x <= 0) || (boost::math::isinf)(x))
1711 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);
1712 if((y <= 0) || (boost::math::isinf)(y))
1713 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);
1714
1715 if(x <= tools::min_value<T>())
1716 {
1717
1718 T shift = ldexp(T(1), tools::digits<T>());
1719 return shift * tgamma_ratio_imp(T(x * shift), y, pol);
1720 }
1721
1722 if((x < max_factorial<T>::value) && (y < max_factorial<T>::value))
1723 {
1724
1725 return boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
1726 }
1727 T prefix = 1;
1728 if(x < 1)
1729 {
1730 if(y < 2 * max_factorial<T>::value)
1731 {
1732
1733
1734 prefix /= x;
1735 x += 1;
1736 while(y >= max_factorial<T>::value)
1737 {
1738 y -= 1;
1739 prefix /= y;
1740 }
1741 return prefix * boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
1742 }
1743
1744
1745
1746 return exp(boost::math::lgamma(x, pol) - boost::math::lgamma(y, pol));
1747 }
1748 if(y < 1)
1749 {
1750 if(x < 2 * max_factorial<T>::value)
1751 {
1752
1753
1754 prefix *= y;
1755 y += 1;
1756 while(x >= max_factorial<T>::value)
1757 {
1758 x -= 1;
1759 prefix *= x;
1760 }
1761 return prefix * boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
1762 }
1763
1764
1765
1766 return exp(boost::math::lgamma(x, pol) - boost::math::lgamma(y, pol));
1767 }
1768
1769
1770
1771 return boost::math::tgamma_delta_ratio(x, y - x, pol);
1772 }
1773
1774 template <class T, class Policy>
1775 T gamma_p_derivative_imp(T a, T x, const Policy& pol)
1776 {
1777 BOOST_MATH_STD_USING
1778
1779
1780
1781 if(a <= 0)
1782 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);
1783 if(x < 0)
1784 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);
1785
1786
1787
1788 if(x == 0)
1789 {
1790 return (a > 1) ? 0 :
1791 (a == 1) ? 1 : policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
1792 }
1793
1794
1795
1796 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1797 T f1 = detail::regularised_gamma_prefix(a, x, pol, lanczos_type());
1798 if((x < 1) && (tools::max_value<T>() * x < f1))
1799 {
1800
1801 return policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
1802 }
1803 if(f1 == 0)
1804 {
1805
1806 f1 = a * log(x) - x - lgamma(a, pol) - log(x);
1807 f1 = exp(f1);
1808 }
1809 else
1810 f1 /= x;
1811
1812 return f1;
1813 }
1814
1815 template <class T, class Policy>
1816 inline typename tools::promote_args<T>::type
1817 tgamma(T z, const Policy& , const std::true_type)
1818 {
1819 BOOST_FPU_EXCEPTION_GUARD
1820 typedef typename tools::promote_args<T>::type result_type;
1821 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1822 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1823 typedef typename policies::normalise<
1824 Policy,
1825 policies::promote_float<false>,
1826 policies::promote_double<false>,
1827 policies::discrete_quantile<>,
1828 policies::assert_undefined<> >::type forwarding_policy;
1829 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%)");
1830 }
1831
1832 template <class T, class Policy>
1833 struct igamma_initializer
1834 {
1835 struct init
1836 {
1837 init()
1838 {
1839 typedef typename policies::precision<T, Policy>::type precision_type;
1840
1841 typedef std::integral_constant<int,
1842 precision_type::value <= 0 ? 0 :
1843 precision_type::value <= 53 ? 53 :
1844 precision_type::value <= 64 ? 64 :
1845 precision_type::value <= 113 ? 113 : 0
1846 > tag_type;
1847
1848 do_init(tag_type());
1849 }
1850 template <int N>
1851 static void do_init(const std::integral_constant<int, N>&)
1852 {
1853
1854
1855
1856
1857 if(std::numeric_limits<T>::digits)
1858 {
1859 boost::math::gamma_p(static_cast<T>(400), static_cast<T>(400), Policy());
1860 }
1861 }
1862 static void do_init(const std::integral_constant<int, 53>&){}
1863 void force_instantiate()const{}
1864 };
1865 static const init initializer;
1866 static void force_instantiate()
1867 {
1868 initializer.force_instantiate();
1869 }
1870 };
1871
1872 template <class T, class Policy>
1873 const typename igamma_initializer<T, Policy>::init igamma_initializer<T, Policy>::initializer;
1874
1875 template <class T, class Policy>
1876 struct lgamma_initializer
1877 {
1878 struct init
1879 {
1880 init()
1881 {
1882 typedef typename policies::precision<T, Policy>::type precision_type;
1883 typedef std::integral_constant<int,
1884 precision_type::value <= 0 ? 0 :
1885 precision_type::value <= 64 ? 64 :
1886 precision_type::value <= 113 ? 113 : 0
1887 > tag_type;
1888
1889 do_init(tag_type());
1890 }
1891 static void do_init(const std::integral_constant<int, 64>&)
1892 {
1893 boost::math::lgamma(static_cast<T>(2.5), Policy());
1894 boost::math::lgamma(static_cast<T>(1.25), Policy());
1895 boost::math::lgamma(static_cast<T>(1.75), Policy());
1896 }
1897 static void do_init(const std::integral_constant<int, 113>&)
1898 {
1899 boost::math::lgamma(static_cast<T>(2.5), Policy());
1900 boost::math::lgamma(static_cast<T>(1.25), Policy());
1901 boost::math::lgamma(static_cast<T>(1.5), Policy());
1902 boost::math::lgamma(static_cast<T>(1.75), Policy());
1903 }
1904 static void do_init(const std::integral_constant<int, 0>&)
1905 {
1906 }
1907 void force_instantiate()const{}
1908 };
1909 static const init initializer;
1910 static void force_instantiate()
1911 {
1912 initializer.force_instantiate();
1913 }
1914 };
1915
1916 template <class T, class Policy>
1917 const typename lgamma_initializer<T, Policy>::init lgamma_initializer<T, Policy>::initializer;
1918
1919 template <class T1, class T2, class Policy>
1920 inline tools::promote_args_t<T1, T2>
1921 tgamma(T1 a, T2 z, const Policy&, const std::false_type)
1922 {
1923 BOOST_FPU_EXCEPTION_GUARD
1924 typedef tools::promote_args_t<T1, T2> result_type;
1925 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1926
1927 typedef typename policies::normalise<
1928 Policy,
1929 policies::promote_float<false>,
1930 policies::promote_double<false>,
1931 policies::discrete_quantile<>,
1932 policies::assert_undefined<> >::type forwarding_policy;
1933
1934 igamma_initializer<value_type, forwarding_policy>::force_instantiate();
1935
1936 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
1937 detail::gamma_incomplete_imp(static_cast<value_type>(a),
1938 static_cast<value_type>(z), false, true,
1939 forwarding_policy(), static_cast<value_type*>(nullptr)), "boost::math::tgamma<%1%>(%1%, %1%)");
1940 }
1941
1942 template <class T1, class T2>
1943 inline tools::promote_args_t<T1, T2>
1944 tgamma(T1 a, T2 z, const std::false_type& tag)
1945 {
1946 return tgamma(a, z, policies::policy<>(), tag);
1947 }
1948
1949
1950 }
1951
1952 template <class T>
1953 inline typename tools::promote_args<T>::type
1954 tgamma(T z)
1955 {
1956 return tgamma(z, policies::policy<>());
1957 }
1958
1959 template <class T, class Policy>
1960 inline typename tools::promote_args<T>::type
1961 lgamma(T z, int* sign, const Policy&)
1962 {
1963 BOOST_FPU_EXCEPTION_GUARD
1964 typedef typename tools::promote_args<T>::type result_type;
1965 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1966 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1967 typedef typename policies::normalise<
1968 Policy,
1969 policies::promote_float<false>,
1970 policies::promote_double<false>,
1971 policies::discrete_quantile<>,
1972 policies::assert_undefined<> >::type forwarding_policy;
1973
1974 detail::lgamma_initializer<value_type, forwarding_policy>::force_instantiate();
1975
1976 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%)");
1977 }
1978
1979 template <class T>
1980 inline typename tools::promote_args<T>::type
1981 lgamma(T z, int* sign)
1982 {
1983 return lgamma(z, sign, policies::policy<>());
1984 }
1985
1986 template <class T, class Policy>
1987 inline typename tools::promote_args<T>::type
1988 lgamma(T x, const Policy& pol)
1989 {
1990 return ::boost::math::lgamma(x, nullptr, pol);
1991 }
1992
1993 template <class T>
1994 inline typename tools::promote_args<T>::type
1995 lgamma(T x)
1996 {
1997 return ::boost::math::lgamma(x, nullptr, policies::policy<>());
1998 }
1999
2000 template <class T, class Policy>
2001 inline typename tools::promote_args<T>::type
2002 tgamma1pm1(T z, const Policy& )
2003 {
2004 BOOST_FPU_EXCEPTION_GUARD
2005 typedef typename tools::promote_args<T>::type result_type;
2006 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2007 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2008 typedef typename policies::normalise<
2009 Policy,
2010 policies::promote_float<false>,
2011 policies::promote_double<false>,
2012 policies::discrete_quantile<>,
2013 policies::assert_undefined<> >::type forwarding_policy;
2014
2015 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%)");
2016 }
2017
2018 template <class T>
2019 inline typename tools::promote_args<T>::type
2020 tgamma1pm1(T z)
2021 {
2022 return tgamma1pm1(z, policies::policy<>());
2023 }
2024
2025
2026
2027
2028 template <class T1, class T2>
2029 inline tools::promote_args_t<T1, T2>
2030 tgamma(T1 a, T2 z)
2031 {
2032
2033
2034
2035
2036 using maybe_policy = typename policies::is_policy<T2>::type;
2037 using result_type = tools::promote_args_t<T1, T2>;
2038 return static_cast<result_type>(detail::tgamma(a, z, maybe_policy()));
2039 }
2040 template <class T1, class T2, class Policy>
2041 inline tools::promote_args_t<T1, T2>
2042 tgamma(T1 a, T2 z, const Policy& pol)
2043 {
2044 using result_type = tools::promote_args_t<T1, T2>;
2045 return static_cast<result_type>(detail::tgamma(a, z, pol, std::false_type()));
2046 }
2047
2048
2049
2050 template <class T1, class T2, class Policy>
2051 inline tools::promote_args_t<T1, T2>
2052 tgamma_lower(T1 a, T2 z, const Policy&)
2053 {
2054 BOOST_FPU_EXCEPTION_GUARD
2055 typedef tools::promote_args_t<T1, T2> result_type;
2056 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2057
2058 typedef typename policies::normalise<
2059 Policy,
2060 policies::promote_float<false>,
2061 policies::promote_double<false>,
2062 policies::discrete_quantile<>,
2063 policies::assert_undefined<> >::type forwarding_policy;
2064
2065 detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2066
2067 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2068 detail::gamma_incomplete_imp(static_cast<value_type>(a),
2069 static_cast<value_type>(z), false, false,
2070 forwarding_policy(), static_cast<value_type*>(nullptr)), "tgamma_lower<%1%>(%1%, %1%)");
2071 }
2072 template <class T1, class T2>
2073 inline tools::promote_args_t<T1, T2>
2074 tgamma_lower(T1 a, T2 z)
2075 {
2076 return tgamma_lower(a, z, policies::policy<>());
2077 }
2078
2079
2080
2081 template <class T1, class T2, class Policy>
2082 inline tools::promote_args_t<T1, T2>
2083 gamma_q(T1 a, T2 z, const Policy& )
2084 {
2085 BOOST_FPU_EXCEPTION_GUARD
2086 typedef tools::promote_args_t<T1, T2> result_type;
2087 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2088
2089 typedef typename policies::normalise<
2090 Policy,
2091 policies::promote_float<false>,
2092 policies::promote_double<false>,
2093 policies::discrete_quantile<>,
2094 policies::assert_undefined<> >::type forwarding_policy;
2095
2096 detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2097
2098 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2099 detail::gamma_incomplete_imp(static_cast<value_type>(a),
2100 static_cast<value_type>(z), true, true,
2101 forwarding_policy(), static_cast<value_type*>(nullptr)), "gamma_q<%1%>(%1%, %1%)");
2102 }
2103 template <class T1, class T2>
2104 inline tools::promote_args_t<T1, T2>
2105 gamma_q(T1 a, T2 z)
2106 {
2107 return gamma_q(a, z, policies::policy<>());
2108 }
2109
2110
2111
2112 template <class T1, class T2, class Policy>
2113 inline tools::promote_args_t<T1, T2>
2114 gamma_p(T1 a, T2 z, const Policy&)
2115 {
2116 BOOST_FPU_EXCEPTION_GUARD
2117 typedef tools::promote_args_t<T1, T2> result_type;
2118 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2119
2120 typedef typename policies::normalise<
2121 Policy,
2122 policies::promote_float<false>,
2123 policies::promote_double<false>,
2124 policies::discrete_quantile<>,
2125 policies::assert_undefined<> >::type forwarding_policy;
2126
2127 detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2128
2129 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2130 detail::gamma_incomplete_imp(static_cast<value_type>(a),
2131 static_cast<value_type>(z), true, false,
2132 forwarding_policy(), static_cast<value_type*>(nullptr)), "gamma_p<%1%>(%1%, %1%)");
2133 }
2134 template <class T1, class T2>
2135 inline tools::promote_args_t<T1, T2>
2136 gamma_p(T1 a, T2 z)
2137 {
2138 return gamma_p(a, z, policies::policy<>());
2139 }
2140
2141
2142 template <class T1, class T2, class Policy>
2143 inline tools::promote_args_t<T1, T2>
2144 tgamma_delta_ratio(T1 z, T2 delta, const Policy& )
2145 {
2146 BOOST_FPU_EXCEPTION_GUARD
2147 typedef tools::promote_args_t<T1, T2> result_type;
2148 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2149 typedef typename policies::normalise<
2150 Policy,
2151 policies::promote_float<false>,
2152 policies::promote_double<false>,
2153 policies::discrete_quantile<>,
2154 policies::assert_undefined<> >::type forwarding_policy;
2155
2156 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%)");
2157 }
2158 template <class T1, class T2>
2159 inline tools::promote_args_t<T1, T2>
2160 tgamma_delta_ratio(T1 z, T2 delta)
2161 {
2162 return tgamma_delta_ratio(z, delta, policies::policy<>());
2163 }
2164 template <class T1, class T2, class Policy>
2165 inline tools::promote_args_t<T1, T2>
2166 tgamma_ratio(T1 a, T2 b, const Policy&)
2167 {
2168 typedef tools::promote_args_t<T1, T2> result_type;
2169 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2170 typedef typename policies::normalise<
2171 Policy,
2172 policies::promote_float<false>,
2173 policies::promote_double<false>,
2174 policies::discrete_quantile<>,
2175 policies::assert_undefined<> >::type forwarding_policy;
2176
2177 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%)");
2178 }
2179 template <class T1, class T2>
2180 inline tools::promote_args_t<T1, T2>
2181 tgamma_ratio(T1 a, T2 b)
2182 {
2183 return tgamma_ratio(a, b, policies::policy<>());
2184 }
2185
2186 template <class T1, class T2, class Policy>
2187 inline tools::promote_args_t<T1, T2>
2188 gamma_p_derivative(T1 a, T2 x, const Policy&)
2189 {
2190 BOOST_FPU_EXCEPTION_GUARD
2191 typedef tools::promote_args_t<T1, T2> result_type;
2192 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2193 typedef typename policies::normalise<
2194 Policy,
2195 policies::promote_float<false>,
2196 policies::promote_double<false>,
2197 policies::discrete_quantile<>,
2198 policies::assert_undefined<> >::type forwarding_policy;
2199
2200 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%)");
2201 }
2202 template <class T1, class T2>
2203 inline tools::promote_args_t<T1, T2>
2204 gamma_p_derivative(T1 a, T2 x)
2205 {
2206 return gamma_p_derivative(a, x, policies::policy<>());
2207 }
2208
2209 }
2210 }
2211
2212 #ifdef _MSC_VER
2213 # pragma warning(pop)
2214 #endif
2215
2216 #include <boost/math/special_functions/detail/igamma_inverse.hpp>
2217 #include <boost/math/special_functions/detail/gamma_inva.hpp>
2218 #include <boost/math/special_functions/erf.hpp>
2219
2220 #endif