File indexing completed on 2025-07-15 08:38:19
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 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
0855
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
0864
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
0880
0881
0882
0883
0884
0885
0886
0887 if((z <= tools::log_min_value<T>()) || (a < 1 / tools::max_value<T>()))
0888 {
0889
0890 return exp(a * log(z) - z - lgamma_imp(a, pol, l));
0891 }
0892 else
0893 {
0894
0895
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
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
0909
0910
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
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
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
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
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
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
0976
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
0994
0995
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
1004
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
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
1023
1024
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
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
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
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
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
1107 *p_derivative = sqrt(x) * exp(-x) / constants::root_pi<T>();
1108 }
1109 return e;
1110 }
1111
1112
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
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;
1160
1161 if(a >= max_factorial<T>::value && !normalised)
1162 {
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173 if(invert && (a * 4 < x))
1174 {
1175
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
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
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
1206
1207
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
1245 invert = !invert;
1246 eval_method = 0;
1247 }
1248 else if(is_half_int && (x > 0.2))
1249 {
1250
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
1261 invert = !invert;
1262 eval_method = 7;
1263 }
1264 else if(x < T(0.5))
1265 {
1266
1267
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
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
1296
1297
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
1307
1308
1309
1310
1311
1312
1313 if(20 / a > sigma * sigma)
1314 use_temme = true;
1315 }
1316 else if(policies::digits<T, Policy>() <= 64)
1317 {
1318
1319
1320
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
1333
1334
1335
1336
1337
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
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
1379
1380
1381
1382
1383
1384
1385
1386
1387
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
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
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
1442
1443
1444
1445
1446
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
1467
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
1493
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
1515
1516 if((x < 1) && (tools::max_value<T>() * x < *p_derivative))
1517 {
1518
1519 *p_derivative = tools::max_value<T>() / 2;
1520 }
1521
1522 *p_derivative /= x;
1523 }
1524
1525 return result;
1526 }
1527
1528
1529
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
1539
1540
1541
1542
1543
1544
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
1565
1566
1567
1568
1569 result = exp(-delta);
1570 }
1571 else
1572
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
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
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
1601
1602
1603
1604
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
1616
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
1628
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
1635
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
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
1667
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
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
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
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
1736
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
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
1756
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
1768
1769 return exp(boost::math::lgamma(x, pol) - boost::math::lgamma(y, pol));
1770 }
1771
1772
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
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
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
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
1804 return policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
1805 }
1806 if(f1 == 0)
1807 {
1808
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& , 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
1857
1858
1859
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
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 }
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& )
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
2030
2031 template <class T1, class T2>
2032 inline tools::promote_args_t<T1, T2>
2033 tgamma(T1 a, T2 z)
2034 {
2035
2036
2037
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
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
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
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& )
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
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
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
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
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& )
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 }
2213 }
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