Warning, file /include/boost/math/special_functions/gamma.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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/config.hpp>
0018 #include <boost/math/tools/series.hpp>
0019 #include <boost/math/tools/fraction.hpp>
0020 #include <boost/math/tools/precision.hpp>
0021 #include <boost/math/tools/promotion.hpp>
0022 #include <boost/math/tools/type_traits.hpp>
0023 #include <boost/math/tools/numeric_limits.hpp>
0024 #include <boost/math/tools/cstdint.hpp>
0025 #include <boost/math/tools/assert.hpp>
0026 #include <boost/math/policies/error_handling.hpp>
0027 #include <boost/math/constants/constants.hpp>
0028 #include <boost/math/special_functions/math_fwd.hpp>
0029 #include <boost/math/special_functions/log1p.hpp>
0030 #include <boost/math/special_functions/trunc.hpp>
0031 #include <boost/math/special_functions/powm1.hpp>
0032 #include <boost/math/special_functions/sqrt1pm1.hpp>
0033 #include <boost/math/special_functions/lanczos.hpp>
0034 #include <boost/math/special_functions/fpclassify.hpp>
0035 #include <boost/math/special_functions/detail/igamma_large.hpp>
0036 #include <boost/math/special_functions/detail/unchecked_factorial.hpp>
0037 #include <boost/math/special_functions/detail/lgamma_small.hpp>
0038
0039
0040 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0041 #include <boost/math/special_functions/bernoulli.hpp>
0042 #include <boost/math/special_functions/polygamma.hpp>
0043 #endif
0044
0045 #ifdef _MSC_VER
0046 # pragma warning(push)
0047 # pragma warning(disable: 4702)
0048 # pragma warning(disable: 4127)
0049 # pragma warning(disable: 4100)
0050 # pragma warning(disable: 6326)
0051
0052
0053
0054
0055 #endif
0056
0057 namespace boost{ namespace math{
0058
0059 namespace detail{
0060
0061 template <class T>
0062 BOOST_MATH_GPU_ENABLED inline bool is_odd(T v, const boost::math::true_type&)
0063 {
0064 int i = static_cast<int>(v);
0065 return i&1;
0066 }
0067 template <class T>
0068 BOOST_MATH_GPU_ENABLED inline bool is_odd(T v, const boost::math::false_type&)
0069 {
0070
0071 BOOST_MATH_STD_USING
0072 T modulus = v - 2 * floor(v/2);
0073 return static_cast<bool>(modulus != 0);
0074 }
0075 template <class T>
0076 BOOST_MATH_GPU_ENABLED inline bool is_odd(T v)
0077 {
0078 return is_odd(v, ::boost::math::is_convertible<T, int>());
0079 }
0080
0081 template <class T>
0082 BOOST_MATH_GPU_ENABLED T sinpx(T z)
0083 {
0084
0085
0086 BOOST_MATH_STD_USING
0087 int sign = 1;
0088 if(z < 0)
0089 {
0090 z = -z;
0091 }
0092 T fl = floor(z);
0093 T dist;
0094 if(is_odd(fl))
0095 {
0096 fl += 1;
0097 dist = fl - z;
0098 sign = -sign;
0099 }
0100 else
0101 {
0102 dist = z - fl;
0103 }
0104 BOOST_MATH_ASSERT(fl >= 0);
0105 if(dist > T(0.5))
0106 dist = 1 - dist;
0107 T result = sin(dist*boost::math::constants::pi<T>());
0108 return sign*z*result;
0109 }
0110
0111
0112
0113 template <class T, class Policy, class Lanczos>
0114 BOOST_MATH_GPU_ENABLED T gamma_imp_final(T z, const Policy& pol, const Lanczos& l)
0115 {
0116 BOOST_MATH_STD_USING
0117
0118 (void)l;
0119
0120 T result = 1;
0121
0122 #ifdef BOOST_MATH_INSTRUMENT
0123 static bool b = false;
0124 if(!b)
0125 {
0126 std::cout << "tgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl;
0127 b = true;
0128 }
0129 #endif
0130 constexpr auto function = "boost::math::tgamma<%1%>(%1%)";
0131
0132 if(z <= 0)
0133 {
0134 if(floor(z) == z)
0135 {
0136 return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
0137 }
0138
0139
0140 while(z < 0)
0141 {
0142 result /= z;
0143 z += 1;
0144 }
0145 }
0146 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0147 if((floor(z) == z) && (z < max_factorial<T>::value))
0148 {
0149 result *= unchecked_factorial<T>(itrunc(z, pol) - 1);
0150 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0151 }
0152 else if (z < tools::root_epsilon<T>())
0153 {
0154 if (z < 1 / tools::max_value<T>())
0155 result = policies::raise_overflow_error<T>(function, nullptr, pol);
0156 result *= 1 / z - constants::euler<T>();
0157 }
0158 else
0159 {
0160 result *= Lanczos::lanczos_sum(z);
0161 T zgh = (z + static_cast<T>(Lanczos::g()) - boost::math::constants::half<T>());
0162 T lzgh = log(zgh);
0163 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0164 BOOST_MATH_INSTRUMENT_VARIABLE(tools::log_max_value<T>());
0165 if(z * lzgh > tools::log_max_value<T>())
0166 {
0167
0168 BOOST_MATH_INSTRUMENT_VARIABLE(zgh);
0169 if(lzgh * z / 2 > tools::log_max_value<T>())
0170 return boost::math::sign(result) * policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0171 T hp = pow(zgh, T((z / 2) - T(0.25)));
0172 BOOST_MATH_INSTRUMENT_VARIABLE(hp);
0173 result *= hp / exp(zgh);
0174 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0175 if(tools::max_value<T>() / hp < result)
0176 return boost::math::sign(result) * policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0177 result *= hp;
0178 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0179 }
0180 else
0181 {
0182 BOOST_MATH_INSTRUMENT_VARIABLE(zgh);
0183 BOOST_MATH_INSTRUMENT_VARIABLE(pow(zgh, T(z - boost::math::constants::half<T>())));
0184 BOOST_MATH_INSTRUMENT_VARIABLE(exp(zgh));
0185 result *= pow(zgh, T(z - boost::math::constants::half<T>())) / exp(zgh);
0186 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0187 }
0188 }
0189 return result;
0190 }
0191
0192 #ifdef BOOST_MATH_ENABLE_CUDA
0193 # pragma nv_diag_suppress 2190
0194 #endif
0195
0196
0197 template <class T, class Policy, class Lanczos>
0198 BOOST_MATH_GPU_ENABLED BOOST_MATH_FORCEINLINE T gamma_imp(T z, const Policy& pol, const Lanczos& l)
0199 {
0200 BOOST_MATH_STD_USING
0201
0202 T result = 1;
0203 constexpr auto function = "boost::math::tgamma<%1%>(%1%)";
0204
0205 if(z <= 0)
0206 {
0207 if(floor(z) == z)
0208 return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
0209 if(z <= -20)
0210 {
0211 result = gamma_imp_final(T(-z), pol, l) * sinpx(z);
0212 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0213 if((fabs(result) < 1) && (tools::max_value<T>() * fabs(result) < boost::math::constants::pi<T>()))
0214 return -boost::math::sign(result) * policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0215 result = -boost::math::constants::pi<T>() / result;
0216 if(result == 0)
0217 return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
0218 if((boost::math::fpclassify)(result) == BOOST_MATH_FP_SUBNORMAL)
0219 return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", result, pol);
0220 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0221 return result;
0222 }
0223 }
0224
0225 return gamma_imp_final(T(z), pol, l);
0226 }
0227
0228 #ifdef BOOST_MATH_ENABLE_CUDA
0229 # pragma nv_diag_default 2190
0230 #endif
0231
0232
0233
0234
0235 template <class T, class Policy, class Lanczos>
0236 BOOST_MATH_GPU_ENABLED T lgamma_imp_final(T z, const Policy& pol, const Lanczos& l, int* sign = nullptr)
0237 {
0238 #ifdef BOOST_MATH_INSTRUMENT
0239 static bool b = false;
0240 if(!b)
0241 {
0242 std::cout << "lgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl;
0243 b = true;
0244 }
0245 #endif
0246
0247 BOOST_MATH_STD_USING
0248
0249 constexpr auto function = "boost::math::lgamma<%1%>(%1%)";
0250
0251 T result = 0;
0252 int sresult = 1;
0253
0254 if (z < tools::root_epsilon<T>())
0255 {
0256 if (0 == z)
0257 return policies::raise_pole_error<T>(function, "Evaluation of lgamma at %1%.", z, pol);
0258 if (4 * fabs(z) < tools::epsilon<T>())
0259 result = -log(fabs(z));
0260 else
0261 result = log(fabs(1 / z - constants::euler<T>()));
0262 if (z < 0)
0263 sresult = -1;
0264 }
0265 else if(z < 15)
0266 {
0267 typedef typename policies::precision<T, Policy>::type precision_type;
0268 typedef boost::math::integral_constant<int,
0269 precision_type::value <= 0 ? 0 :
0270 precision_type::value <= 64 ? 64 :
0271 precision_type::value <= 113 ? 113 : 0
0272 > tag_type;
0273
0274 result = lgamma_small_imp<T>(z, T(z - 1), T(z - 2), tag_type(), pol, l);
0275 }
0276 else if((z >= 3) && (z < 100) && (boost::math::numeric_limits<T>::max_exponent >= 1024))
0277 {
0278
0279 result = log(gamma_imp(z, pol, l));
0280 }
0281 else
0282 {
0283
0284 T zgh = static_cast<T>(z + T(Lanczos::g()) - boost::math::constants::half<T>());
0285 result = log(zgh) - 1;
0286 result *= z - 0.5f;
0287
0288
0289
0290 if(result * tools::epsilon<T>() < 20)
0291 result += log(Lanczos::lanczos_sum_expG_scaled(z));
0292 }
0293
0294 if(sign)
0295 *sign = sresult;
0296 return result;
0297 }
0298
0299 #ifdef BOOST_MATH_ENABLE_CUDA
0300 # pragma nv_diag_suppress 2190
0301 #endif
0302
0303 template <class T, class Policy, class Lanczos>
0304 BOOST_MATH_GPU_ENABLED BOOST_MATH_FORCEINLINE T lgamma_imp(T z, const Policy& pol, const Lanczos& l, int* sign = nullptr)
0305 {
0306 BOOST_MATH_STD_USING
0307
0308 if(z <= -tools::root_epsilon<T>())
0309 {
0310 constexpr auto function = "boost::math::lgamma<%1%>(%1%)";
0311
0312 T result = 0;
0313 int sresult = 1;
0314
0315
0316 if(floor(z) == z)
0317 return policies::raise_pole_error<T>(function, "Evaluation of lgamma at a negative integer %1%.", z, pol);
0318
0319 T t = sinpx(z);
0320 z = -z;
0321 if(t < 0)
0322 {
0323 t = -t;
0324 }
0325 else
0326 {
0327 sresult = -sresult;
0328 }
0329 result = log(boost::math::constants::pi<T>()) - lgamma_imp_final(T(z), pol, l) - log(t);
0330
0331 if(sign)
0332 {
0333 *sign = sresult;
0334 }
0335
0336 return result;
0337 }
0338 else
0339 {
0340 return lgamma_imp_final(T(z), pol, l, sign);
0341 }
0342 }
0343
0344 #ifdef BOOST_MATH_ENABLE_CUDA
0345 # pragma nv_diag_default 2190
0346 #endif
0347
0348
0349
0350
0351 template <class T>
0352 struct upper_incomplete_gamma_fract
0353 {
0354 private:
0355 T z, a;
0356 int k;
0357 public:
0358 typedef boost::math::pair<T,T> result_type;
0359
0360 BOOST_MATH_GPU_ENABLED upper_incomplete_gamma_fract(T a1, T z1)
0361 : z(z1-a1+1), a(a1), k(0)
0362 {
0363 }
0364
0365 BOOST_MATH_GPU_ENABLED result_type operator()()
0366 {
0367 ++k;
0368 z += 2;
0369 return result_type(k * (a - k), z);
0370 }
0371 };
0372
0373 template <class T>
0374 BOOST_MATH_GPU_ENABLED inline T upper_gamma_fraction(T a, T z, T eps)
0375 {
0376
0377
0378
0379 upper_incomplete_gamma_fract<T> f(a, z);
0380 return 1 / (z - a + 1 + boost::math::tools::continued_fraction_a(f, eps));
0381 }
0382
0383 template <class T>
0384 struct lower_incomplete_gamma_series
0385 {
0386 private:
0387 T a, z, result;
0388 public:
0389 typedef T result_type;
0390 BOOST_MATH_GPU_ENABLED lower_incomplete_gamma_series(T a1, T z1) : a(a1), z(z1), result(1){}
0391
0392 BOOST_MATH_GPU_ENABLED T operator()()
0393 {
0394 T r = result;
0395 a += 1;
0396 result *= z/a;
0397 return r;
0398 }
0399 };
0400
0401 template <class T, class Policy>
0402 BOOST_MATH_GPU_ENABLED inline T lower_gamma_series(T a, T z, const Policy& pol, T init_value = 0)
0403 {
0404
0405
0406
0407 lower_incomplete_gamma_series<T> s(a, z);
0408 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0409 T factor = policies::get_epsilon<T, Policy>();
0410 T result = boost::math::tools::sum_series(s, factor, max_iter, init_value);
0411 policies::check_series_iterations<T>("boost::math::detail::lower_gamma_series<%1%>(%1%)", max_iter, pol);
0412 return result;
0413 }
0414
0415 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0416
0417
0418
0419
0420
0421 template<class T>
0422 boost::math::size_t highest_bernoulli_index()
0423 {
0424 const float digits10_of_type = (boost::math::numeric_limits<T>::is_specialized
0425 ? static_cast<float>(boost::math::numeric_limits<T>::digits10)
0426 : static_cast<float>(boost::math::tools::digits<T>() * 0.301F));
0427
0428
0429 return static_cast<boost::math::size_t>(18.0F + (0.6F * digits10_of_type));
0430 }
0431
0432 template<class T>
0433 int minimum_argument_for_bernoulli_recursion()
0434 {
0435 BOOST_MATH_STD_USING
0436
0437 const float digits10_of_type = (boost::math::numeric_limits<T>::is_specialized
0438 ? (float) boost::math::numeric_limits<T>::digits10
0439 : (float) (boost::math::tools::digits<T>() * 0.301F));
0440
0441 int min_arg = (int) (digits10_of_type * 1.7F);
0442
0443 if(digits10_of_type < 50.0F)
0444 {
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457 const float d2_minus_one = ((digits10_of_type / 0.301F) - 1.0F);
0458 const float limit = ceil(exp((d2_minus_one * log(2.0F)) / 20.0F));
0459
0460 min_arg = (int) (BOOST_MATH_GPU_SAFE_MIN(digits10_of_type * 1.7F, limit));
0461 }
0462
0463 return min_arg;
0464 }
0465
0466 template <class T, class Policy>
0467 T scaled_tgamma_no_lanczos(const T& z, const Policy& pol, bool islog = false)
0468 {
0469 BOOST_MATH_STD_USING
0470
0471
0472
0473
0474
0475 BOOST_MATH_ASSERT(minimum_argument_for_bernoulli_recursion<T>() <= z);
0476
0477
0478
0479 const boost::math::size_t number_of_bernoullis_b2n = policies::get_max_series_iterations<Policy>();
0480
0481 T one_over_x_pow_two_n_minus_one = 1 / z;
0482 const T one_over_x2 = one_over_x_pow_two_n_minus_one * one_over_x_pow_two_n_minus_one;
0483 T sum = (boost::math::bernoulli_b2n<T>(1) / 2) * one_over_x_pow_two_n_minus_one;
0484 const T target_epsilon_to_break_loop = sum * boost::math::tools::epsilon<T>();
0485 const T half_ln_two_pi_over_z = sqrt(boost::math::constants::two_pi<T>() / z);
0486 T last_term = 2 * sum;
0487
0488 for (boost::math::size_t n = 2U;; ++n)
0489 {
0490 one_over_x_pow_two_n_minus_one *= one_over_x2;
0491
0492 const boost::math::size_t n2 = static_cast<boost::math::size_t>(n * 2U);
0493
0494 const T term = (boost::math::bernoulli_b2n<T>(static_cast<int>(n)) * one_over_x_pow_two_n_minus_one) / (n2 * (n2 - 1U));
0495
0496 if ((n >= 3U) && (abs(term) < target_epsilon_to_break_loop))
0497 {
0498
0499
0500
0501
0502
0503 break;
0504 }
0505 if (n > number_of_bernoullis_b2n)
0506 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);
0507
0508 sum += term;
0509
0510
0511 T fterm = fabs(term);
0512 if(fterm > last_term)
0513 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);
0514 last_term = fterm;
0515 }
0516
0517
0518 T scaled_gamma_value = islog ? T(sum + log(half_ln_two_pi_over_z)) : T(exp(sum) * half_ln_two_pi_over_z);
0519 return scaled_gamma_value;
0520 }
0521
0522
0523 template <class T, class Policy>
0524 T lgamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos&, int* sign = nullptr);
0525
0526 template <class T, class Policy>
0527 T gamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos&)
0528 {
0529 BOOST_MATH_STD_USING
0530
0531 constexpr auto function = "boost::math::tgamma<%1%>(%1%)";
0532
0533
0534 const bool is_at_zero = (z == 0);
0535
0536 if((boost::math::isnan)(z) || (is_at_zero) || ((boost::math::isinf)(z) && (z < 0)))
0537 return policies::raise_domain_error<T>(function, "Evaluation of tgamma at %1%.", z, pol);
0538
0539 const bool b_neg = (z < 0);
0540
0541 const bool floor_of_z_is_equal_to_z = (floor(z) == z);
0542
0543
0544 if((!b_neg) && floor_of_z_is_equal_to_z && (z < boost::math::max_factorial<T>::value))
0545 {
0546 return boost::math::unchecked_factorial<T>(itrunc(z) - 1);
0547 }
0548
0549
0550 T zz((!b_neg) ? z : -z);
0551
0552
0553 if(zz < tools::cbrt_epsilon<T>())
0554 {
0555 const T a0(1);
0556 const T a1(boost::math::constants::euler<T>());
0557 const T six_euler_squared((boost::math::constants::euler<T>() * boost::math::constants::euler<T>()) * 6);
0558 const T a2((six_euler_squared - boost::math::constants::pi_sqr<T>()) / 12);
0559
0560 const T inverse_tgamma_series = z * ((a2 * z + a1) * z + a0);
0561
0562 return 1 / inverse_tgamma_series;
0563 }
0564
0565
0566
0567 const int min_arg_for_recursion = minimum_argument_for_bernoulli_recursion<T>();
0568
0569 int n_recur;
0570
0571 if(zz < min_arg_for_recursion)
0572 {
0573 n_recur = boost::math::itrunc(min_arg_for_recursion - zz) + 1;
0574
0575 zz += n_recur;
0576 }
0577 else
0578 {
0579 n_recur = 0;
0580 }
0581 if (!n_recur)
0582 {
0583 if (zz > tools::log_max_value<T>())
0584 return policies::raise_overflow_error<T>(function, nullptr, pol);
0585 if (log(zz) * zz / 2 > tools::log_max_value<T>())
0586 return policies::raise_overflow_error<T>(function, nullptr, pol);
0587 }
0588 T gamma_value = scaled_tgamma_no_lanczos(zz, pol);
0589 T power_term = pow(zz, zz / 2);
0590 T exp_term = exp(-zz);
0591 gamma_value *= (power_term * exp_term);
0592 if(!n_recur && (tools::max_value<T>() / power_term < gamma_value))
0593 return policies::raise_overflow_error<T>(function, nullptr, pol);
0594 gamma_value *= power_term;
0595
0596
0597 if(n_recur)
0598 {
0599
0600
0601
0602
0603
0604 zz = fabs(z) + 1;
0605 for(int k = 1; k < n_recur; ++k)
0606 {
0607 gamma_value /= zz;
0608 zz += 1;
0609 }
0610 gamma_value /= fabs(z);
0611 }
0612
0613
0614 if(b_neg)
0615 {
0616
0617
0618
0619
0620
0621 if(floor_of_z_is_equal_to_z)
0622 return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
0623
0624 gamma_value *= sinpx(z);
0625
0626 BOOST_MATH_INSTRUMENT_VARIABLE(gamma_value);
0627
0628 const bool result_is_too_large_to_represent = ( (abs(gamma_value) < 1)
0629 && ((tools::max_value<T>() * abs(gamma_value)) < boost::math::constants::pi<T>()));
0630
0631 if(result_is_too_large_to_represent)
0632 return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
0633
0634 gamma_value = -boost::math::constants::pi<T>() / gamma_value;
0635 BOOST_MATH_INSTRUMENT_VARIABLE(gamma_value);
0636
0637 if(gamma_value == 0)
0638 return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
0639
0640 if((boost::math::fpclassify)(gamma_value) == static_cast<int>(BOOST_MATH_FP_SUBNORMAL))
0641 return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", gamma_value, pol);
0642 }
0643
0644 return gamma_value;
0645 }
0646
0647 template <class T, class Policy>
0648 inline T log_gamma_near_1(const T& z, Policy const& pol)
0649 {
0650
0651
0652
0653
0654
0655 BOOST_MATH_STD_USING
0656
0657 BOOST_MATH_ASSERT(fabs(z) < 1);
0658
0659 T result = -constants::euler<T>() * z;
0660
0661 T power_term = z * z / 2;
0662 int n = 2;
0663 T term = 0;
0664
0665 do
0666 {
0667 term = power_term * boost::math::polygamma(n - 1, T(1), pol);
0668 result += term;
0669 ++n;
0670 power_term *= z / n;
0671 } while (fabs(result) * tools::epsilon<T>() < fabs(term));
0672
0673 return result;
0674 }
0675
0676 template <class T, class Policy>
0677 T lgamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos&, int* sign)
0678 {
0679 BOOST_MATH_STD_USING
0680
0681 constexpr auto function = "boost::math::lgamma<%1%>(%1%)";
0682
0683
0684 const bool is_at_zero = (z == 0);
0685
0686 if(is_at_zero)
0687 return policies::raise_domain_error<T>(function, "Evaluation of lgamma at zero %1%.", z, pol);
0688 if((boost::math::isnan)(z))
0689 return policies::raise_domain_error<T>(function, "Evaluation of lgamma at %1%.", z, pol);
0690 if((boost::math::isinf)(z))
0691 return policies::raise_overflow_error<T>(function, nullptr, pol);
0692
0693 const bool b_neg = (z < 0);
0694
0695 const bool floor_of_z_is_equal_to_z = (floor(z) == z);
0696
0697
0698 if((!b_neg) && floor_of_z_is_equal_to_z && (z < boost::math::max_factorial<T>::value))
0699 {
0700 if (sign)
0701 *sign = 1;
0702 return log(boost::math::unchecked_factorial<T>(itrunc(z) - 1));
0703 }
0704
0705
0706 T zz((!b_neg) ? z : -z);
0707
0708 const int min_arg_for_recursion = minimum_argument_for_bernoulli_recursion<T>();
0709
0710 T log_gamma_value;
0711
0712 if (zz < min_arg_for_recursion)
0713 {
0714
0715
0716
0717 if (sign)
0718 * sign = 1;
0719 if(fabs(z - 1) < 0.25)
0720 {
0721 log_gamma_value = log_gamma_near_1(T(zz - 1), pol);
0722 }
0723 else if(fabs(z - 2) < 0.25)
0724 {
0725 log_gamma_value = log_gamma_near_1(T(zz - 2), pol) + log(zz - 1);
0726 }
0727 else if (z > -tools::root_epsilon<T>())
0728 {
0729
0730
0731 if (sign)
0732 *sign = z < 0 ? -1 : 1;
0733 return log(abs(gamma_imp(z, pol, lanczos::undefined_lanczos())));
0734 }
0735 else
0736 {
0737
0738
0739 T g = gamma_imp(zz, pol, lanczos::undefined_lanczos());
0740 if (sign)
0741 {
0742 *sign = g < 0 ? -1 : 1;
0743 }
0744 log_gamma_value = log(abs(g));
0745 }
0746 }
0747 else
0748 {
0749
0750 T sum = scaled_tgamma_no_lanczos(zz, pol, true);
0751 log_gamma_value = zz * (log(zz) - 1) + sum;
0752 }
0753
0754 int sign_of_result = 1;
0755
0756 if(b_neg)
0757 {
0758
0759
0760
0761
0762 if(floor_of_z_is_equal_to_z)
0763 return policies::raise_pole_error<T>(function, "Evaluation of lgamma at a negative integer %1%.", z, pol);
0764
0765 T t = sinpx(z);
0766
0767 if(t < 0)
0768 {
0769 t = -t;
0770 }
0771 else
0772 {
0773 sign_of_result = -sign_of_result;
0774 }
0775
0776 log_gamma_value = - log_gamma_value
0777 + log(boost::math::constants::pi<T>())
0778 - log(t);
0779 }
0780
0781 if(sign != static_cast<int*>(nullptr)) { *sign = sign_of_result; }
0782
0783 return log_gamma_value;
0784 }
0785
0786 #endif
0787
0788
0789
0790 #ifdef BOOST_MATH_HAS_NVRTC
0791 template <class RT>
0792 BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT> tgamma(RT z);
0793
0794 template <class RT1, class RT2>
0795 BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> tgamma(RT1 a, RT2 z);
0796
0797 template <class RT1, class RT2, class Policy>
0798 BOOST_MATH_GPU_ENABLED tools::promote_args_t<RT1, RT2> tgamma(RT1 a, RT2 z, const Policy& pol);
0799 #endif
0800
0801
0802
0803
0804
0805 template <class T, class Policy, class Lanczos>
0806 BOOST_MATH_GPU_ENABLED T tgammap1m1_imp(T dz, Policy const& pol, const Lanczos& l)
0807 {
0808 BOOST_MATH_STD_USING
0809
0810 typedef typename policies::precision<T,Policy>::type precision_type;
0811
0812 typedef boost::math::integral_constant<int,
0813 precision_type::value <= 0 ? 0 :
0814 precision_type::value <= 64 ? 64 :
0815 precision_type::value <= 113 ? 113 : 0
0816 > tag_type;
0817
0818 T result;
0819 if(dz < 0)
0820 {
0821 if(dz < T(-0.5))
0822 {
0823
0824 #ifdef BOOST_MATH_HAS_NVRTC
0825 result = ::tgamma(1+dz);
0826 #else
0827 result = boost::math::tgamma(1+dz, pol) - 1;
0828 #endif
0829 BOOST_MATH_INSTRUMENT_CODE(result);
0830 }
0831 else
0832 {
0833
0834 result = boost::math::expm1(-boost::math::log1p(dz, pol)
0835 + lgamma_small_imp<T>(dz+2, dz + 1, dz, tag_type(), pol, l), pol);
0836 BOOST_MATH_INSTRUMENT_CODE(result);
0837 }
0838 }
0839 else
0840 {
0841 if(dz < 2)
0842 {
0843
0844 result = boost::math::expm1(lgamma_small_imp<T>(dz+1, dz, dz-1, tag_type(), pol, l), pol);
0845 BOOST_MATH_INSTRUMENT_CODE(result);
0846 }
0847 else
0848 {
0849
0850 #ifdef BOOST_MATH_HAS_NVRTC
0851 result = ::tgamma(1+dz);
0852 #else
0853 result = boost::math::tgamma(1+dz, pol) - 1;
0854 #endif
0855 BOOST_MATH_INSTRUMENT_CODE(result);
0856 }
0857 }
0858
0859 return result;
0860 }
0861
0862 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0863
0864 template <class T, class Policy>
0865 inline T tgammap1m1_imp(T z, Policy const& pol,
0866 const ::boost::math::lanczos::undefined_lanczos&)
0867 {
0868 BOOST_MATH_STD_USING
0869
0870 if(fabs(z) < T(0.55))
0871 {
0872 return boost::math::expm1(log_gamma_near_1(z, pol));
0873 }
0874 return boost::math::expm1(boost::math::lgamma(1 + z, pol));
0875 }
0876
0877 #endif
0878
0879
0880
0881
0882 template <class T>
0883 struct small_gamma2_series
0884 {
0885 typedef T result_type;
0886
0887 BOOST_MATH_GPU_ENABLED small_gamma2_series(T a_, T x_) : result(-x_), x(-x_), apn(a_+1), n(1){}
0888
0889 BOOST_MATH_GPU_ENABLED T operator()()
0890 {
0891 T r = result / (apn);
0892 result *= x;
0893 result /= ++n;
0894 apn += 1;
0895 return r;
0896 }
0897
0898 private:
0899 T result, x, apn;
0900 int n;
0901 };
0902
0903
0904
0905
0906 template <class T, class Policy>
0907 BOOST_MATH_GPU_ENABLED T full_igamma_prefix(T a, T z, const Policy& pol)
0908 {
0909 BOOST_MATH_STD_USING
0910
0911 if (z > tools::max_value<T>())
0912 return 0;
0913
0914 T alz = a * log(z);
0915
0916 T prefix { };
0917
0918 if(z >= 1)
0919 {
0920 if((alz < tools::log_max_value<T>()) && (-z > tools::log_min_value<T>()))
0921 {
0922 prefix = pow(z, a) * exp(-z);
0923 }
0924 else if(a >= 1)
0925 {
0926 prefix = pow(T(z / exp(z/a)), a);
0927 }
0928 else
0929 {
0930 prefix = exp(alz - z);
0931 }
0932 }
0933 else
0934 {
0935 if(alz > tools::log_min_value<T>())
0936 {
0937 prefix = pow(z, a) * exp(-z);
0938 }
0939 else if(z/a < tools::log_max_value<T>())
0940 {
0941 prefix = pow(T(z / exp(z/a)), a);
0942 }
0943 else
0944 {
0945 prefix = exp(alz - z);
0946 }
0947 }
0948
0949
0950
0951
0952 if((boost::math::fpclassify)(prefix) == (int)BOOST_MATH_FP_INFINITE)
0953 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);
0954
0955 return prefix;
0956 }
0957
0958
0959
0960
0961 template <class T, class Policy, class Lanczos>
0962 BOOST_MATH_GPU_ENABLED T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l)
0963 {
0964 BOOST_MATH_STD_USING
0965 if (z >= tools::max_value<T>())
0966 return 0;
0967 T agh = a + static_cast<T>(Lanczos::g()) - T(0.5);
0968 T prefix;
0969 T d = ((z - a) - static_cast<T>(Lanczos::g()) + T(0.5)) / agh;
0970
0971 if(a < 1)
0972 {
0973
0974
0975
0976
0977
0978
0979
0980
0981
0982 if((z <= tools::log_min_value<T>()) || (a < 1 / tools::max_value<T>()))
0983 {
0984
0985 return exp(a * log(z) - z - lgamma_imp(a, pol, l));
0986 }
0987 else
0988 {
0989
0990
0991 return pow(z, a) * exp(-z) / gamma_imp(a, pol, l);
0992 }
0993 }
0994 else if((fabs(d*d*a) <= 100) && (a > 150))
0995 {
0996
0997 prefix = a * boost::math::log1pmx(d, pol) + z * static_cast<T>(0.5 - Lanczos::g()) / agh;
0998 prefix = exp(prefix);
0999 }
1000 else
1001 {
1002
1003
1004
1005
1006
1007 T alz = a * log(z / agh);
1008 T amz = a - z;
1009 if((BOOST_MATH_GPU_SAFE_MIN(alz, amz) <= tools::log_min_value<T>()) || (BOOST_MATH_GPU_SAFE_MAX(alz, amz) >= tools::log_max_value<T>()))
1010 {
1011 T amza = amz / a;
1012 if((BOOST_MATH_GPU_SAFE_MIN(alz, amz)/2 > tools::log_min_value<T>()) && (BOOST_MATH_GPU_SAFE_MAX(alz, amz)/2 < tools::log_max_value<T>()))
1013 {
1014
1015 T sq = pow(z / agh, a / 2) * exp(amz / 2);
1016 prefix = sq * sq;
1017 }
1018 else if((BOOST_MATH_GPU_SAFE_MIN(alz, amz)/4 > tools::log_min_value<T>()) && (BOOST_MATH_GPU_SAFE_MAX(alz, amz)/4 < tools::log_max_value<T>()) && (z > a))
1019 {
1020
1021 T sq = pow(z / agh, a / 4) * exp(amz / 4);
1022 prefix = sq * sq;
1023 prefix *= prefix;
1024 }
1025 else if((amza > tools::log_min_value<T>()) && (amza < tools::log_max_value<T>()))
1026 {
1027 prefix = pow(T((z * exp(amza)) / agh), a);
1028 }
1029 else
1030 {
1031 prefix = exp(alz + amz);
1032 }
1033 }
1034 else
1035 {
1036 prefix = pow(T(z / agh), a) * exp(amz);
1037 }
1038 }
1039 prefix *= sqrt(agh / boost::math::constants::e<T>()) / Lanczos::lanczos_sum_expG_scaled(a);
1040 return prefix;
1041 }
1042
1043 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
1044
1045
1046
1047
1048 template <class T, class Policy>
1049 T regularised_gamma_prefix(T a, T z, const Policy& pol, const lanczos::undefined_lanczos& l)
1050 {
1051 BOOST_MATH_STD_USING
1052
1053 if((a < 1) && (z < 1))
1054 {
1055
1056 return pow(z, a) * exp(-z) / boost::math::tgamma(a, pol);
1057 }
1058 else if(a > minimum_argument_for_bernoulli_recursion<T>())
1059 {
1060 T scaled_gamma = scaled_tgamma_no_lanczos(a, pol);
1061 T power_term = pow(z / a, a / 2);
1062 T a_minus_z = a - z;
1063 if ((0 == power_term) || (fabs(a_minus_z) > tools::log_max_value<T>()))
1064 {
1065
1066 return exp(a * log(z / a) + a_minus_z - log(scaled_gamma));
1067 }
1068 return (power_term * exp(a_minus_z)) * (power_term / scaled_gamma);
1069 }
1070 else
1071 {
1072
1073
1074
1075
1076 const int min_z = minimum_argument_for_bernoulli_recursion<T>();
1077 long shift = 1 + ltrunc(min_z - a);
1078 T result = regularised_gamma_prefix(T(a + shift), z, pol, l);
1079 if (result != 0)
1080 {
1081 for (long i = 0; i < shift; ++i)
1082 {
1083 result /= z;
1084 result *= a + i;
1085 }
1086 return result;
1087 }
1088 else
1089 {
1090
1091
1092
1093
1094
1095 T scaled_gamma = scaled_tgamma_no_lanczos(T(a + shift), pol);
1096 T power_term_1 = pow(T(z / (a + shift)), a);
1097 T power_term_2 = pow(T(a + shift), T(-shift));
1098 T power_term_3 = exp(a + shift - z);
1099 if ((0 == power_term_1) || (0 == power_term_2) || (0 == power_term_3) || (fabs(a + shift - z) > tools::log_max_value<T>()))
1100 {
1101
1102
1103 return exp(a * log(z) - z - boost::math::lgamma(a, pol));
1104 }
1105 result = power_term_1 * power_term_2 * power_term_3 / scaled_gamma;
1106 for (long i = 0; i < shift; ++i)
1107 {
1108 result *= a + i;
1109 }
1110 return result;
1111 }
1112 }
1113 }
1114
1115 #endif
1116
1117
1118
1119
1120 template <class T, class Policy>
1121 BOOST_MATH_GPU_ENABLED inline T tgamma_small_upper_part(T a, T x, const Policy& pol, T* pgam = 0, bool invert = false, T* pderivative = 0)
1122 {
1123 BOOST_MATH_STD_USING
1124
1125
1126
1127
1128 #ifdef BOOST_MATH_HAS_NVRTC
1129 typedef typename tools::promote_args<T>::type result_type;
1130 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1131 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1132 T result {detail::tgammap1m1_imp(static_cast<value_type>(a), pol, evaluation_type())};
1133 #else
1134 T result { boost::math::tgamma1pm1(a, pol) };
1135 #endif
1136
1137 if(pgam)
1138 *pgam = (result + 1) / a;
1139 T p = boost::math::powm1(x, a, pol);
1140 result -= p;
1141 result /= a;
1142 detail::small_gamma2_series<T> s(a, x);
1143 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>() - 10;
1144 p += 1;
1145 if(pderivative)
1146 *pderivative = p / (*pgam * exp(x));
1147 T init_value = invert ? *pgam : 0;
1148 result = -p * tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, (init_value - result) / p);
1149 policies::check_series_iterations<T>("boost::math::tgamma_small_upper_part<%1%>(%1%, %1%)", max_iter, pol);
1150 if(invert)
1151 result = -result;
1152 return result;
1153 }
1154
1155
1156
1157 template <class T, class Policy>
1158 BOOST_MATH_GPU_ENABLED inline T finite_gamma_q(T a, T x, Policy const& pol, T* pderivative = 0)
1159 {
1160
1161
1162
1163 BOOST_MATH_STD_USING
1164 T e = exp(-x);
1165 T sum = e;
1166 if(sum != 0)
1167 {
1168 T term = sum;
1169 for(unsigned n = 1; n < a; ++n)
1170 {
1171 term /= n;
1172 term *= x;
1173 sum += term;
1174 }
1175 }
1176 if(pderivative)
1177 {
1178 *pderivative = e * pow(x, a) / boost::math::unchecked_factorial<T>(itrunc(T(a - 1), pol));
1179 }
1180 return sum;
1181 }
1182
1183
1184
1185 template <class T, class Policy>
1186 BOOST_MATH_GPU_ENABLED T finite_half_gamma_q(T a, T x, T* p_derivative, const Policy& pol)
1187 {
1188
1189
1190
1191 BOOST_MATH_STD_USING
1192
1193 #ifdef BOOST_MATH_HAS_NVRTC
1194 T e;
1195 if (boost::math::is_same_v<T, float>)
1196 {
1197 e = ::erfcf(::sqrtf(x));
1198 }
1199 else
1200 {
1201 e = ::erfc(::sqrt(x));
1202 }
1203 #else
1204 T e = boost::math::erfc(sqrt(x), pol);
1205 #endif
1206
1207 if((e != 0) && (a > 1))
1208 {
1209 T term = exp(-x) / sqrt(constants::pi<T>() * x);
1210 term *= x;
1211 static const T half = T(1) / 2;
1212 term /= half;
1213 T sum = term;
1214 for(unsigned n = 2; n < a; ++n)
1215 {
1216 term /= n - half;
1217 term *= x;
1218 sum += term;
1219 }
1220 e += sum;
1221 if(p_derivative)
1222 {
1223 *p_derivative = 0;
1224 }
1225 }
1226 else if(p_derivative)
1227 {
1228
1229 *p_derivative = sqrt(x) * exp(-x) / constants::root_pi<T>();
1230 }
1231 return e;
1232 }
1233
1234
1235
1236 template <class T>
1237 struct incomplete_tgamma_large_x_series
1238 {
1239 typedef T result_type;
1240 BOOST_MATH_GPU_ENABLED incomplete_tgamma_large_x_series(const T& a, const T& x)
1241 : a_poch(a - 1), z(x), term(1) {}
1242 BOOST_MATH_GPU_ENABLED T operator()()
1243 {
1244 T result = term;
1245 term *= a_poch / z;
1246 a_poch -= 1;
1247 return result;
1248 }
1249 T a_poch, z, term;
1250 };
1251
1252 template <class T, class Policy>
1253 BOOST_MATH_GPU_ENABLED T incomplete_tgamma_large_x(const T& a, const T& x, const Policy& pol)
1254 {
1255 BOOST_MATH_STD_USING
1256 incomplete_tgamma_large_x_series<T> s(a, x);
1257 boost::math::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
1258 T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
1259 boost::math::policies::check_series_iterations<T>("boost::math::tgamma<%1%>(%1%,%1%)", max_iter, pol);
1260 return result;
1261 }
1262
1263
1264
1265
1266
1267 template <class T, class Policy>
1268 BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp_final(T a, T x, bool normalised, bool invert,
1269 const Policy& pol, T* p_derivative)
1270 {
1271 constexpr auto function = "boost::math::gamma_p<%1%>(%1%, %1%)";
1272 if(a <= 0)
1273 return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
1274 if(x < 0)
1275 return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
1276
1277 BOOST_MATH_STD_USING
1278
1279 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1280
1281 T result = 0;
1282
1283 BOOST_MATH_ASSERT((p_derivative == nullptr) || normalised);
1284
1285 bool is_int, is_half_int;
1286 bool is_small_a = (a < 30) && (a <= x + 1) && (x < tools::log_max_value<T>());
1287 if(is_small_a)
1288 {
1289 T fa = floor(a);
1290 is_int = (fa == a);
1291 is_half_int = is_int ? false : (fabs(fa - a) == 0.5f);
1292 }
1293 else
1294 {
1295 is_int = is_half_int = false;
1296 }
1297
1298 int eval_method;
1299
1300 if(is_int && (x > 0.6))
1301 {
1302
1303 invert = !invert;
1304 eval_method = 0;
1305 }
1306 else if(is_half_int && (x > 0.2))
1307 {
1308
1309 invert = !invert;
1310 eval_method = 1;
1311 }
1312 else if((x < tools::root_epsilon<T>()) && (a > 1))
1313 {
1314 eval_method = 6;
1315 }
1316 else if ((x > 1000) && ((a < x) || (fabs(a - 50) / x < 1)))
1317 {
1318
1319 invert = !invert;
1320 eval_method = 7;
1321 }
1322 else if(x < T(0.5))
1323 {
1324
1325
1326
1327 if(T(-0.4) / log(x) < a)
1328 {
1329 eval_method = 2;
1330 }
1331 else
1332 {
1333 eval_method = 3;
1334 }
1335 }
1336 else if(x < T(1.1))
1337 {
1338
1339
1340
1341 if(x * 0.75f < a)
1342 {
1343 eval_method = 2;
1344 }
1345 else
1346 {
1347 eval_method = 3;
1348 }
1349 }
1350 else
1351 {
1352
1353
1354
1355
1356
1357 bool use_temme = false;
1358 if(normalised && boost::math::numeric_limits<T>::is_specialized && (a > 20))
1359 {
1360 T sigma = fabs((x-a)/a);
1361 if((a > 200) && (policies::digits<T, Policy>() <= 113))
1362 {
1363
1364
1365
1366
1367
1368
1369
1370
1371 if(20 / a > sigma * sigma)
1372 use_temme = true;
1373 }
1374 else if(policies::digits<T, Policy>() <= 64)
1375 {
1376
1377
1378
1379 if(sigma < 0.4)
1380 use_temme = true;
1381 }
1382 }
1383 if(use_temme)
1384 {
1385 eval_method = 5;
1386 }
1387 else
1388 {
1389
1390
1391
1392
1393
1394
1395
1396
1397 if(x - (1 / (3 * x)) < a)
1398 {
1399 eval_method = 2;
1400 }
1401 else
1402 {
1403 eval_method = 4;
1404 invert = !invert;
1405 }
1406 }
1407 }
1408
1409 switch(eval_method)
1410 {
1411 case 0:
1412 {
1413 result = finite_gamma_q(a, x, pol, p_derivative);
1414 if(!normalised)
1415 {
1416 #ifdef BOOST_MATH_HAS_NVRTC
1417 if (boost::math::is_same_v<T, float>)
1418 {
1419 result *= ::tgammaf(a);
1420 }
1421 else
1422 {
1423 result *= ::tgamma(a);
1424 }
1425 #else
1426 result *= boost::math::tgamma(a, pol);
1427 #endif
1428 }
1429 break;
1430 }
1431 case 1:
1432 {
1433 result = finite_half_gamma_q(a, x, p_derivative, pol);
1434 if(!normalised)
1435 {
1436 #ifdef BOOST_MATH_HAS_NVRTC
1437 if (boost::math::is_same_v<T, float>)
1438 {
1439 result *= ::tgammaf(a);
1440 }
1441 else
1442 {
1443 result *= ::tgamma(a);
1444 }
1445 #else
1446 result *= boost::math::tgamma(a, pol);
1447 #endif
1448 }
1449 if(p_derivative && (*p_derivative == 0))
1450 *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1451 break;
1452 }
1453 case 2:
1454 {
1455
1456 result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1457 if(p_derivative)
1458 *p_derivative = result;
1459 if(result != 0)
1460 {
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473 T init_value = 0;
1474 bool optimised_invert = false;
1475 if(invert)
1476 {
1477 #ifdef BOOST_MATH_HAS_NVRTC
1478 if (boost::math::is_same_v<T, float>)
1479 {
1480 init_value = (normalised ? 1 : ::tgammaf(a));
1481 }
1482 else
1483 {
1484 init_value = (normalised ? 1 : ::tgamma(a));
1485 }
1486 #else
1487 init_value = (normalised ? 1 : boost::math::tgamma(a, pol));
1488 #endif
1489
1490 if(normalised || (result >= 1) || (tools::max_value<T>() * result > init_value))
1491 {
1492 init_value /= result;
1493 if(normalised || (a < 1) || (tools::max_value<T>() / a > init_value))
1494 {
1495 init_value *= -a;
1496 optimised_invert = true;
1497 }
1498 else
1499 init_value = 0;
1500 }
1501 else
1502 init_value = 0;
1503 }
1504 result *= detail::lower_gamma_series(a, x, pol, init_value) / a;
1505 if(optimised_invert)
1506 {
1507 invert = false;
1508 result = -result;
1509 }
1510 }
1511 break;
1512 }
1513 case 3:
1514 {
1515
1516 invert = !invert;
1517 T g;
1518 result = tgamma_small_upper_part(a, x, pol, &g, invert, p_derivative);
1519 invert = false;
1520 if(normalised)
1521 result /= g;
1522 break;
1523 }
1524 case 4:
1525 {
1526
1527 result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1528 if(p_derivative)
1529 *p_derivative = result;
1530 if(result != 0)
1531 result *= upper_gamma_fraction(a, x, policies::get_epsilon<T, Policy>());
1532 break;
1533 }
1534 case 5:
1535 {
1536
1537
1538
1539
1540
1541
1542
1543
1544 typedef typename policies::precision<T, Policy>::type precision_type;
1545
1546 typedef boost::math::integral_constant<int,
1547 precision_type::value <= 0 ? 0 :
1548 precision_type::value <= 53 ? 53 :
1549 precision_type::value <= 64 ? 64 :
1550 precision_type::value <= 113 ? 113 : 0
1551 > tag_type;
1552
1553 result = igamma_temme_large(a, x, pol, tag_type());
1554 if(x >= a)
1555 invert = !invert;
1556 if(p_derivative)
1557 *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1558 break;
1559 }
1560 case 6:
1561 {
1562
1563
1564 if(!normalised)
1565 result = pow(x, a) / (a);
1566 else
1567 {
1568 #ifndef BOOST_MATH_NO_EXCEPTIONS
1569 try
1570 {
1571 #endif
1572 #ifdef BOOST_MATH_HAS_NVRTC
1573 if (boost::math::is_same_v<T, float>)
1574 {
1575 result = ::powf(x, a) / ::tgammaf(a + 1);
1576 }
1577 else
1578 {
1579 result = ::pow(x, a) / ::tgamma(a + 1);
1580 }
1581 #else
1582 result = pow(x, a) / boost::math::tgamma(a + 1, pol);
1583 #endif
1584 #ifndef BOOST_MATH_NO_EXCEPTIONS
1585 }
1586 catch (const std::overflow_error&)
1587 {
1588 result = 0;
1589 }
1590 #endif
1591 }
1592 result *= 1 - a * x / (a + 1);
1593 if (p_derivative)
1594 *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
1595 break;
1596 }
1597 case 7:
1598 {
1599
1600
1601 result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
1602 if (p_derivative)
1603 *p_derivative = result;
1604 result /= x;
1605 if (result != 0)
1606 result *= incomplete_tgamma_large_x(a, x, pol);
1607 break;
1608 }
1609 }
1610
1611 if(normalised && (result > 1))
1612 result = 1;
1613 if(invert)
1614 {
1615 #ifdef BOOST_MATH_HAS_NVRTC
1616 T gam;
1617 if (boost::math::is_same_v<T, float>)
1618 {
1619 gam = normalised ? 1 : ::tgammaf(a);
1620 }
1621 else
1622 {
1623 gam = normalised ? 1 : ::tgamma(a);
1624 }
1625 #else
1626 T gam = normalised ? 1 : boost::math::tgamma(a, pol);
1627 #endif
1628 result = gam - result;
1629 }
1630 if(p_derivative)
1631 {
1632
1633
1634
1635 if((x < 1) && (tools::max_value<T>() * x < *p_derivative))
1636 {
1637
1638 *p_derivative = tools::max_value<T>() / 2;
1639 }
1640
1641 *p_derivative /= x;
1642 }
1643
1644 return result;
1645 }
1646
1647
1648 template <class T, class Policy>
1649 BOOST_MATH_GPU_ENABLED T gamma_incomplete_imp(T a, T x, bool normalised, bool invert,
1650 const Policy& pol, T* p_derivative)
1651 {
1652 constexpr auto function = "boost::math::gamma_p<%1%>(%1%, %1%)";
1653 if(a <= 0)
1654 return policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
1655 if(x < 0)
1656 return policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
1657
1658 BOOST_MATH_STD_USING
1659
1660
1661 T result = 0;
1662
1663 if(a >= max_factorial<T>::value && !normalised)
1664 {
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675 if(invert && (a * 4 < x))
1676 {
1677
1678 result = a * log(x) - x;
1679 if(p_derivative)
1680 *p_derivative = exp(result);
1681 result += log(upper_gamma_fraction(a, x, policies::get_epsilon<T, Policy>()));
1682 }
1683 else if(!invert && (a > 4 * x))
1684 {
1685
1686 result = a * log(x) - x;
1687 if(p_derivative)
1688 *p_derivative = exp(result);
1689 T init_value = 0;
1690 result += log(detail::lower_gamma_series(a, x, pol, init_value) / a);
1691 }
1692 else
1693 {
1694 result = gamma_incomplete_imp_final(T(a), T(x), true, invert, pol, p_derivative);
1695 if(result == 0)
1696 {
1697 if(invert)
1698 {
1699
1700 result = 1 + 1 / (12 * a) + 1 / (288 * a * a);
1701 result = log(result) - a + (a - 0.5f) * log(a) + log(boost::math::constants::root_two_pi<T>());
1702 if(p_derivative)
1703 *p_derivative = exp(a * log(x) - x);
1704 }
1705 else
1706 {
1707
1708
1709
1710 result = a * log(x) - x;
1711 if(p_derivative)
1712 *p_derivative = exp(result);
1713 T init_value = 0;
1714 result += log(detail::lower_gamma_series(a, x, pol, init_value) / a);
1715 }
1716 }
1717 else
1718 {
1719 #ifdef BOOST_MATH_HAS_NVRTC
1720 if (boost::math::is_same_v<T, float>)
1721 {
1722 result = ::logf(result) + ::lgammaf(a);
1723 }
1724 else
1725 {
1726 result = ::log(result) + ::lgamma(a);
1727 }
1728 #else
1729 result = log(result) + boost::math::lgamma(a, pol);
1730 #endif
1731 }
1732 }
1733 if(result > tools::log_max_value<T>())
1734 return policies::raise_overflow_error<T>(function, nullptr, pol);
1735 return exp(result);
1736 }
1737
1738
1739 return gamma_incomplete_imp_final(T(a), T(x), normalised, invert, pol, p_derivative);
1740 }
1741
1742
1743
1744
1745 template <class T, class Policy, class Lanczos>
1746 BOOST_MATH_GPU_ENABLED T tgamma_delta_ratio_imp_lanczos_final(T z, T delta, const Policy& pol, const Lanczos&)
1747 {
1748 BOOST_MATH_STD_USING
1749
1750 T zgh = static_cast<T>(z + T(Lanczos::g()) - constants::half<T>());
1751 T result;
1752 if(z + delta == z)
1753 {
1754 if (fabs(delta / zgh) < boost::math::tools::epsilon<T>())
1755 {
1756
1757
1758
1759
1760
1761 result = exp(-delta);
1762 }
1763 else
1764
1765 result = 1;
1766 }
1767 else
1768 {
1769 if(fabs(delta) < 10)
1770 {
1771 result = exp((constants::half<T>() - z) * boost::math::log1p(delta / zgh, pol));
1772 }
1773 else
1774 {
1775 result = pow(T(zgh / (zgh + delta)), T(z - constants::half<T>()));
1776 }
1777
1778 result *= Lanczos::lanczos_sum(z) / Lanczos::lanczos_sum(T(z + delta));
1779 }
1780 result *= pow(T(constants::e<T>() / (zgh + delta)), delta);
1781 return result;
1782 }
1783
1784 template <class T, class Policy, class Lanczos>
1785 BOOST_MATH_GPU_ENABLED T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const Lanczos& l)
1786 {
1787 BOOST_MATH_STD_USING
1788
1789 if(z < tools::epsilon<T>())
1790 {
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800 if(boost::math::max_factorial<T>::value < delta)
1801 {
1802 T ratio = tgamma_delta_ratio_imp_lanczos_final(T(delta), T(boost::math::max_factorial<T>::value - delta), pol, l);
1803 ratio *= z;
1804 ratio *= boost::math::unchecked_factorial<T>(boost::math::max_factorial<T>::value - 1);
1805 return 1 / ratio;
1806 }
1807 else
1808 {
1809 #ifdef BOOST_MATH_HAS_NVRTC
1810 if (boost::math::is_same_v<T, float>)
1811 {
1812 return 1 / (z * ::tgammaf(z + delta));
1813 }
1814 else
1815 {
1816 return 1 / (z * ::tgamma(z + delta));
1817 }
1818 #else
1819 return 1 / (z * boost::math::tgamma(z + delta, pol));
1820 #endif
1821 }
1822 }
1823
1824 return tgamma_delta_ratio_imp_lanczos_final(T(z), T(delta), pol, l);
1825 }
1826
1827
1828
1829
1830 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
1831
1832 template <class T, class Policy>
1833 T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const lanczos::undefined_lanczos& l)
1834 {
1835 BOOST_MATH_STD_USING
1836
1837
1838
1839
1840
1841
1842
1843
1844 long numerator_shift = 0;
1845 long denominator_shift = 0;
1846 const int min_z = minimum_argument_for_bernoulli_recursion<T>();
1847
1848 if (min_z > z)
1849 numerator_shift = 1 + ltrunc(min_z - z);
1850 if (min_z > z + delta)
1851 denominator_shift = 1 + ltrunc(min_z - z - delta);
1852
1853
1854
1855
1856 if (numerator_shift == 0 && denominator_shift == 0)
1857 {
1858 T scaled_tgamma_num = scaled_tgamma_no_lanczos(z, pol);
1859 T scaled_tgamma_denom = scaled_tgamma_no_lanczos(T(z + delta), pol);
1860 T result = scaled_tgamma_num / scaled_tgamma_denom;
1861 result *= exp(z * boost::math::log1p(-delta / (z + delta), pol)) * pow(T((delta + z) / constants::e<T>()), -delta);
1862 return result;
1863 }
1864
1865
1866
1867
1868 T zz = z + numerator_shift;
1869 T dd = delta - (numerator_shift - denominator_shift);
1870 T ratio = tgamma_delta_ratio_imp_lanczos(zz, dd, pol, l);
1871
1872
1873
1874
1875 for (long long i = 0; i < numerator_shift; ++i)
1876 {
1877 ratio /= (z + i);
1878 if (i < denominator_shift)
1879 ratio *= (z + delta + i);
1880 }
1881 for (long long i = numerator_shift; i < denominator_shift; ++i)
1882 {
1883 ratio *= (z + delta + i);
1884 }
1885 return ratio;
1886 }
1887
1888 #endif
1889
1890 template <class T, class Policy>
1891 BOOST_MATH_GPU_ENABLED T tgamma_delta_ratio_imp(T z, T delta, const Policy& pol)
1892 {
1893 BOOST_MATH_STD_USING
1894
1895 if((z <= 0) || (z + delta <= 0))
1896 {
1897
1898 #ifdef BOOST_MATH_HAS_NVRTC
1899 if (boost::math::is_same_v<T, float>)
1900 {
1901 return ::tgammaf(z) / ::tgammaf(z + delta);
1902 }
1903 else
1904 {
1905 return ::tgamma(z) / ::tgamma(z + delta);
1906 }
1907 #else
1908 return boost::math::tgamma(z, pol) / boost::math::tgamma(z + delta, pol);
1909 #endif
1910 }
1911
1912 if(floor(delta) == delta)
1913 {
1914 if(floor(z) == z)
1915 {
1916
1917
1918
1919
1920 if((z <= max_factorial<T>::value) && (z + delta <= max_factorial<T>::value))
1921 {
1922 return unchecked_factorial<T>((unsigned)itrunc(z, pol) - 1) / unchecked_factorial<T>((unsigned)itrunc(T(z + delta), pol) - 1);
1923 }
1924 }
1925 if(fabs(delta) < 20)
1926 {
1927
1928
1929
1930 if(delta == 0)
1931 return 1;
1932 if(delta < 0)
1933 {
1934 z -= 1;
1935 T result = z;
1936 while(0 != (delta += 1))
1937 {
1938 z -= 1;
1939 result *= z;
1940 }
1941 return result;
1942 }
1943 else
1944 {
1945 T result = 1 / z;
1946 while(0 != (delta -= 1))
1947 {
1948 z += 1;
1949 result /= z;
1950 }
1951 return result;
1952 }
1953 }
1954 }
1955 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1956 return tgamma_delta_ratio_imp_lanczos(z, delta, pol, lanczos_type());
1957 }
1958
1959 template <class T, class Policy>
1960 BOOST_MATH_GPU_ENABLED T tgamma_ratio_imp(T x, T y, const Policy& pol)
1961 {
1962 BOOST_MATH_STD_USING
1963
1964 if((x <= 0) || (boost::math::isinf)(x))
1965 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);
1966 if((y <= 0) || (boost::math::isinf)(y))
1967 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);
1968
1969
1970
1971 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
1972 if(x <= tools::min_value<T>())
1973 {
1974
1975 T shift = ldexp(T(1), tools::digits<T>());
1976 return shift * tgamma_ratio_imp(T(x * shift), y, pol);
1977 }
1978 #endif
1979
1980 if((x < max_factorial<T>::value) && (y < max_factorial<T>::value))
1981 {
1982
1983 #ifdef BOOST_MATH_HAS_NVRTC
1984 if (boost::math::is_same_v<T, float>)
1985 {
1986 return ::tgammaf(x) / ::tgammaf(y);
1987 }
1988 else
1989 {
1990 return ::tgamma(x) / ::tgamma(y);
1991 }
1992 #else
1993 return boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
1994 #endif
1995 }
1996 T prefix = 1;
1997 if(x < 1)
1998 {
1999 if(y < 2 * max_factorial<T>::value)
2000 {
2001
2002
2003 prefix /= x;
2004 x += 1;
2005 while(y >= max_factorial<T>::value)
2006 {
2007 y -= 1;
2008 prefix /= y;
2009 }
2010
2011 #ifdef BOOST_MATH_HAS_NVRTC
2012 if (boost::math::is_same_v<T, float>)
2013 {
2014 return prefix * ::tgammaf(x) / ::tgammaf(y);
2015 }
2016 else
2017 {
2018 return prefix * ::tgamma(x) / ::tgamma(y);
2019 }
2020 #else
2021 return prefix * boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
2022 #endif
2023 }
2024
2025
2026
2027 #ifdef BOOST_MATH_HAS_NVRTC
2028 if (boost::math::is_same_v<T, float>)
2029 {
2030 return ::expf(::lgammaf(x) - ::lgammaf(y));
2031 }
2032 else
2033 {
2034 return ::exp(::lgamma(x) - ::lgamma(y));
2035 }
2036 #else
2037 return exp(boost::math::lgamma(x, pol) - boost::math::lgamma(y, pol));
2038 #endif
2039 }
2040 if(y < 1)
2041 {
2042 if(x < 2 * max_factorial<T>::value)
2043 {
2044
2045
2046 prefix *= y;
2047 y += 1;
2048 while(x >= max_factorial<T>::value)
2049 {
2050 x -= 1;
2051 prefix *= x;
2052 }
2053
2054 #ifdef BOOST_MATH_HAS_NVRTC
2055 if (boost::math::is_same_v<T, float>)
2056 {
2057 return prefix * ::tgammaf(x) / ::tgammaf(y);
2058 }
2059 else
2060 {
2061 return prefix * ::tgamma(x) / ::tgamma(y);
2062 }
2063 #else
2064 return prefix * boost::math::tgamma(x, pol) / boost::math::tgamma(y, pol);
2065 #endif
2066 }
2067
2068
2069
2070 #ifdef BOOST_MATH_HAS_NVRTC
2071 if (boost::math::is_same_v<T, float>)
2072 {
2073 return ::expf(::lgammaf(x) - ::lgammaf(y));
2074 }
2075 else
2076 {
2077 return ::exp(::lgamma(x) - ::lgamma(y));
2078 }
2079 #else
2080 return exp(boost::math::lgamma(x, pol) - boost::math::lgamma(y, pol));
2081 #endif
2082 }
2083
2084
2085
2086 #ifdef BOOST_MATH_HAS_NVRTC
2087 return detail::tgamma_delta_ratio_imp(x, y - x, pol);
2088 #else
2089 return boost::math::tgamma_delta_ratio(x, y - x, pol);
2090 #endif
2091 }
2092
2093 template <class T, class Policy>
2094 BOOST_MATH_GPU_ENABLED T gamma_p_derivative_imp(T a, T x, const Policy& pol)
2095 {
2096 BOOST_MATH_STD_USING
2097
2098
2099
2100 if(a <= 0)
2101 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);
2102 if(x < 0)
2103 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);
2104
2105
2106
2107 if(x == 0)
2108 {
2109 return (a > 1) ? 0 :
2110 (a == 1) ? 1 : policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
2111 }
2112
2113
2114
2115 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
2116 T f1 = detail::regularised_gamma_prefix(a, x, pol, lanczos_type());
2117 if((x < 1) && (tools::max_value<T>() * x < f1))
2118 {
2119
2120 return policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", nullptr, pol);
2121 }
2122 if(f1 == 0)
2123 {
2124
2125 #ifdef BOOST_MATH_HAS_NVRTC
2126 if (boost::math::is_same_v<T, float>)
2127 {
2128 f1 = a * ::logf(x) - x - ::lgammaf(a) - ::logf(x);
2129 }
2130 else
2131 {
2132 f1 = a * ::log(x) - x - ::lgamma(a) - ::log(x);
2133 }
2134 #else
2135 f1 = a * log(x) - x - lgamma(a, pol) - log(x);
2136 #endif
2137 f1 = exp(f1);
2138 }
2139 else
2140 f1 /= x;
2141
2142 return f1;
2143 }
2144
2145 template <class T, class Policy>
2146 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2147 tgamma(T z, const Policy& , const boost::math::true_type)
2148 {
2149 BOOST_FPU_EXCEPTION_GUARD
2150 typedef typename tools::promote_args<T>::type result_type;
2151 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2152 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2153 typedef typename policies::normalise<
2154 Policy,
2155 policies::promote_float<false>,
2156 policies::promote_double<false>,
2157 policies::discrete_quantile<>,
2158 policies::assert_undefined<> >::type forwarding_policy;
2159 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%)");
2160 }
2161
2162 template <class T, class Policy>
2163 struct igamma_initializer
2164 {
2165 struct init
2166 {
2167 BOOST_MATH_GPU_ENABLED init()
2168 {
2169 typedef typename policies::precision<T, Policy>::type precision_type;
2170
2171 typedef boost::math::integral_constant<int,
2172 precision_type::value <= 0 ? 0 :
2173 precision_type::value <= 53 ? 53 :
2174 precision_type::value <= 64 ? 64 :
2175 precision_type::value <= 113 ? 113 : 0
2176 > tag_type;
2177
2178 do_init(tag_type());
2179 }
2180 template <int N>
2181 BOOST_MATH_GPU_ENABLED static void do_init(const boost::math::integral_constant<int, N>&)
2182 {
2183
2184
2185
2186
2187 if (boost::math::numeric_limits<T>::digits)
2188 {
2189 boost::math::gamma_p(static_cast<T>(400), static_cast<T>(400), Policy());
2190 }
2191 }
2192 BOOST_MATH_GPU_ENABLED static void do_init(const boost::math::integral_constant<int, 53>&){}
2193 BOOST_MATH_GPU_ENABLED void force_instantiate()const{}
2194 };
2195 BOOST_MATH_STATIC const init initializer;
2196 BOOST_MATH_GPU_ENABLED static void force_instantiate()
2197 {
2198 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
2199 initializer.force_instantiate();
2200 #endif
2201 }
2202 };
2203
2204 template <class T, class Policy>
2205 const typename igamma_initializer<T, Policy>::init igamma_initializer<T, Policy>::initializer;
2206
2207 template <class T, class Policy>
2208 struct lgamma_initializer
2209 {
2210 struct init
2211 {
2212 BOOST_MATH_GPU_ENABLED init()
2213 {
2214 typedef typename policies::precision<T, Policy>::type precision_type;
2215 typedef boost::math::integral_constant<int,
2216 precision_type::value <= 0 ? 0 :
2217 precision_type::value <= 64 ? 64 :
2218 precision_type::value <= 113 ? 113 : 0
2219 > tag_type;
2220
2221 do_init(tag_type());
2222 }
2223 BOOST_MATH_GPU_ENABLED static void do_init(const boost::math::integral_constant<int, 64>&)
2224 {
2225 boost::math::lgamma(static_cast<T>(2.5), Policy());
2226 boost::math::lgamma(static_cast<T>(1.25), Policy());
2227 boost::math::lgamma(static_cast<T>(1.75), Policy());
2228 }
2229 BOOST_MATH_GPU_ENABLED static void do_init(const boost::math::integral_constant<int, 113>&)
2230 {
2231 boost::math::lgamma(static_cast<T>(2.5), Policy());
2232 boost::math::lgamma(static_cast<T>(1.25), Policy());
2233 boost::math::lgamma(static_cast<T>(1.5), Policy());
2234 boost::math::lgamma(static_cast<T>(1.75), Policy());
2235 }
2236 BOOST_MATH_GPU_ENABLED static void do_init(const boost::math::integral_constant<int, 0>&)
2237 {
2238 }
2239 BOOST_MATH_GPU_ENABLED void force_instantiate()const{}
2240 };
2241 BOOST_MATH_STATIC const init initializer;
2242 BOOST_MATH_GPU_ENABLED static void force_instantiate()
2243 {
2244 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
2245 initializer.force_instantiate();
2246 #endif
2247 }
2248 };
2249
2250 template <class T, class Policy>
2251 const typename lgamma_initializer<T, Policy>::init lgamma_initializer<T, Policy>::initializer;
2252
2253 template <class T1, class T2, class Policy>
2254 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2255 tgamma(T1 a, T2 z, const Policy&, const boost::math::false_type)
2256 {
2257 BOOST_FPU_EXCEPTION_GUARD
2258 typedef tools::promote_args_t<T1, T2> result_type;
2259 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2260
2261 typedef typename policies::normalise<
2262 Policy,
2263 policies::promote_float<false>,
2264 policies::promote_double<false>,
2265 policies::discrete_quantile<>,
2266 policies::assert_undefined<> >::type forwarding_policy;
2267
2268 igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2269
2270 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2271 detail::gamma_incomplete_imp(static_cast<value_type>(a),
2272 static_cast<value_type>(z), false, true,
2273 forwarding_policy(), static_cast<value_type*>(nullptr)), "boost::math::tgamma<%1%>(%1%, %1%)");
2274 }
2275
2276 template <class T1, class T2>
2277 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2278 tgamma(T1 a, T2 z, const boost::math::false_type& tag)
2279 {
2280 return tgamma(a, z, policies::policy<>(), tag);
2281 }
2282
2283
2284 }
2285
2286 template <class T, class Policy>
2287 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2288 lgamma(T z, int* sign, const Policy&)
2289 {
2290 BOOST_FPU_EXCEPTION_GUARD
2291 typedef typename tools::promote_args<T>::type result_type;
2292 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2293 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2294 typedef typename policies::normalise<
2295 Policy,
2296 policies::promote_float<false>,
2297 policies::promote_double<false>,
2298 policies::discrete_quantile<>,
2299 policies::assert_undefined<> >::type forwarding_policy;
2300
2301 detail::lgamma_initializer<value_type, forwarding_policy>::force_instantiate();
2302
2303 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%)");
2304 }
2305
2306 template <class T>
2307 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2308 lgamma(T z, int* sign)
2309 {
2310 return lgamma(z, sign, policies::policy<>());
2311 }
2312
2313 template <class T, class Policy>
2314 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2315 lgamma(T x, const Policy& pol)
2316 {
2317 return ::boost::math::lgamma(x, nullptr, pol);
2318 }
2319
2320 template <class T>
2321 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2322 lgamma(T x)
2323 {
2324 return ::boost::math::lgamma(x, nullptr, policies::policy<>());
2325 }
2326
2327 template <class T, class Policy>
2328 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2329 tgamma1pm1(T z, const Policy& )
2330 {
2331 BOOST_FPU_EXCEPTION_GUARD
2332 typedef typename tools::promote_args<T>::type result_type;
2333 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2334 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
2335 typedef typename policies::normalise<
2336 Policy,
2337 policies::promote_float<false>,
2338 policies::promote_double<false>,
2339 policies::discrete_quantile<>,
2340 policies::assert_undefined<> >::type forwarding_policy;
2341
2342 return policies::checked_narrowing_cast<typename boost::math::remove_cv<result_type>::type, forwarding_policy>(detail::tgammap1m1_imp(static_cast<value_type>(z), forwarding_policy(), evaluation_type()), "boost::math::tgamma1pm1<%!%>(%1%)");
2343 }
2344
2345 template <class T>
2346 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2347 tgamma1pm1(T z)
2348 {
2349 return tgamma1pm1(z, policies::policy<>());
2350 }
2351
2352
2353
2354
2355 template <class T1, class T2>
2356 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2357 tgamma(T1 a, T2 z)
2358 {
2359
2360
2361
2362
2363 using maybe_policy = typename policies::is_policy<T2>::type;
2364 using result_type = tools::promote_args_t<T1, T2>;
2365 return static_cast<result_type>(detail::tgamma(a, z, maybe_policy()));
2366 }
2367 template <class T1, class T2, class Policy>
2368 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2369 tgamma(T1 a, T2 z, const Policy& pol)
2370 {
2371 using result_type = tools::promote_args_t<T1, T2>;
2372 return static_cast<result_type>(detail::tgamma(a, z, pol, boost::math::false_type()));
2373 }
2374 template <class T>
2375 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T>::type
2376 tgamma(T z)
2377 {
2378 return tgamma(z, policies::policy<>());
2379 }
2380
2381
2382
2383 template <class T1, class T2, class Policy>
2384 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2385 tgamma_lower(T1 a, T2 z, const Policy&)
2386 {
2387 BOOST_FPU_EXCEPTION_GUARD
2388 typedef tools::promote_args_t<T1, T2> result_type;
2389 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2390
2391 typedef typename policies::normalise<
2392 Policy,
2393 policies::promote_float<false>,
2394 policies::promote_double<false>,
2395 policies::discrete_quantile<>,
2396 policies::assert_undefined<> >::type forwarding_policy;
2397
2398 detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2399
2400 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2401 detail::gamma_incomplete_imp(static_cast<value_type>(a),
2402 static_cast<value_type>(z), false, false,
2403 forwarding_policy(), static_cast<value_type*>(nullptr)), "tgamma_lower<%1%>(%1%, %1%)");
2404 }
2405 template <class T1, class T2>
2406 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2407 tgamma_lower(T1 a, T2 z)
2408 {
2409 return tgamma_lower(a, z, policies::policy<>());
2410 }
2411
2412
2413
2414 template <class T1, class T2, class Policy>
2415 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2416 gamma_q(T1 a, T2 z, const Policy& )
2417 {
2418 BOOST_FPU_EXCEPTION_GUARD
2419 typedef tools::promote_args_t<T1, T2> result_type;
2420 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2421
2422 typedef typename policies::normalise<
2423 Policy,
2424 policies::promote_float<false>,
2425 policies::promote_double<false>,
2426 policies::discrete_quantile<>,
2427 policies::assert_undefined<> >::type forwarding_policy;
2428
2429 detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2430
2431 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2432 detail::gamma_incomplete_imp(static_cast<value_type>(a),
2433 static_cast<value_type>(z), true, true,
2434 forwarding_policy(), static_cast<value_type*>(nullptr)), "gamma_q<%1%>(%1%, %1%)");
2435 }
2436 template <class T1, class T2>
2437 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2438 gamma_q(T1 a, T2 z)
2439 {
2440 return gamma_q(a, z, policies::policy<>());
2441 }
2442
2443
2444
2445 template <class T1, class T2, class Policy>
2446 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2447 gamma_p(T1 a, T2 z, const Policy&)
2448 {
2449 BOOST_FPU_EXCEPTION_GUARD
2450 typedef tools::promote_args_t<T1, T2> result_type;
2451 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2452
2453 typedef typename policies::normalise<
2454 Policy,
2455 policies::promote_float<false>,
2456 policies::promote_double<false>,
2457 policies::discrete_quantile<>,
2458 policies::assert_undefined<> >::type forwarding_policy;
2459
2460 detail::igamma_initializer<value_type, forwarding_policy>::force_instantiate();
2461
2462 return policies::checked_narrowing_cast<result_type, forwarding_policy>(
2463 detail::gamma_incomplete_imp(static_cast<value_type>(a),
2464 static_cast<value_type>(z), true, false,
2465 forwarding_policy(), static_cast<value_type*>(nullptr)), "gamma_p<%1%>(%1%, %1%)");
2466 }
2467 template <class T1, class T2>
2468 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2469 gamma_p(T1 a, T2 z)
2470 {
2471 return gamma_p(a, z, policies::policy<>());
2472 }
2473
2474
2475 template <class T1, class T2, class Policy>
2476 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2477 tgamma_delta_ratio(T1 z, T2 delta, const Policy& )
2478 {
2479 BOOST_FPU_EXCEPTION_GUARD
2480 typedef tools::promote_args_t<T1, T2> result_type;
2481 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2482 typedef typename policies::normalise<
2483 Policy,
2484 policies::promote_float<false>,
2485 policies::promote_double<false>,
2486 policies::discrete_quantile<>,
2487 policies::assert_undefined<> >::type forwarding_policy;
2488
2489 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%)");
2490 }
2491 template <class T1, class T2>
2492 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2493 tgamma_delta_ratio(T1 z, T2 delta)
2494 {
2495 return tgamma_delta_ratio(z, delta, policies::policy<>());
2496 }
2497 template <class T1, class T2, class Policy>
2498 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2499 tgamma_ratio(T1 a, T2 b, const Policy&)
2500 {
2501 typedef tools::promote_args_t<T1, T2> result_type;
2502 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2503 typedef typename policies::normalise<
2504 Policy,
2505 policies::promote_float<false>,
2506 policies::promote_double<false>,
2507 policies::discrete_quantile<>,
2508 policies::assert_undefined<> >::type forwarding_policy;
2509
2510 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%)");
2511 }
2512 template <class T1, class T2>
2513 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2514 tgamma_ratio(T1 a, T2 b)
2515 {
2516 return tgamma_ratio(a, b, policies::policy<>());
2517 }
2518
2519 template <class T1, class T2, class Policy>
2520 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2521 gamma_p_derivative(T1 a, T2 x, const Policy&)
2522 {
2523 BOOST_FPU_EXCEPTION_GUARD
2524 typedef tools::promote_args_t<T1, T2> result_type;
2525 typedef typename policies::evaluation<result_type, Policy>::type value_type;
2526 typedef typename policies::normalise<
2527 Policy,
2528 policies::promote_float<false>,
2529 policies::promote_double<false>,
2530 policies::discrete_quantile<>,
2531 policies::assert_undefined<> >::type forwarding_policy;
2532
2533 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%)");
2534 }
2535 template <class T1, class T2>
2536 BOOST_MATH_GPU_ENABLED inline tools::promote_args_t<T1, T2>
2537 gamma_p_derivative(T1 a, T2 x)
2538 {
2539 return gamma_p_derivative(a, x, policies::policy<>());
2540 }
2541
2542 }
2543 }
2544
2545 #ifdef _MSC_VER
2546 # pragma warning(pop)
2547 #endif
2548
2549 #include <boost/math/special_functions/detail/igamma_inverse.hpp>
2550 #include <boost/math/special_functions/detail/gamma_inva.hpp>
2551 #include <boost/math/special_functions/erf.hpp>
2552
2553 #endif