Warning, file /include/boost/math/special_functions/beta.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 #ifndef BOOST_MATH_SPECIAL_BETA_HPP
0008 #define BOOST_MATH_SPECIAL_BETA_HPP
0009
0010 #ifdef _MSC_VER
0011 #pragma once
0012 #endif
0013
0014 #include <boost/math/tools/config.hpp>
0015 #include <boost/math/tools/type_traits.hpp>
0016 #include <boost/math/tools/assert.hpp>
0017 #include <boost/math/tools/precision.hpp>
0018 #include <boost/math/tools/numeric_limits.hpp>
0019 #include <boost/math/tools/tuple.hpp>
0020 #include <boost/math/tools/promotion.hpp>
0021 #include <boost/math/tools/cstdint.hpp>
0022 #include <boost/math/special_functions/gamma.hpp>
0023 #include <boost/math/special_functions/erf.hpp>
0024 #include <boost/math/special_functions/log1p.hpp>
0025 #include <boost/math/special_functions/expm1.hpp>
0026 #include <boost/math/special_functions/trunc.hpp>
0027 #include <boost/math/special_functions/lanczos.hpp>
0028 #include <boost/math/policies/policy.hpp>
0029 #include <boost/math/policies/error_handling.hpp>
0030 #include <boost/math/constants/constants.hpp>
0031 #include <boost/math/special_functions/math_fwd.hpp>
0032 #include <boost/math/special_functions/binomial.hpp>
0033 #include <boost/math/special_functions/factorials.hpp>
0034 #include <boost/math/tools/roots.hpp>
0035
0036 namespace boost{ namespace math{
0037
0038 namespace detail{
0039
0040
0041
0042
0043 template <class T, class Lanczos, class Policy>
0044 BOOST_MATH_GPU_ENABLED T beta_imp(T a, T b, const Lanczos&, const Policy& pol)
0045 {
0046 BOOST_MATH_STD_USING
0047
0048 if(a <= 0)
0049 return policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got a=%1%).", a, pol);
0050 if(b <= 0)
0051 return policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got b=%1%).", b, pol);
0052
0053 T result;
0054
0055 T prefix = 1;
0056 T c = a + b;
0057
0058
0059 if((c == a) && (b < tools::epsilon<T>()))
0060 return 1 / b;
0061 else if((c == b) && (a < tools::epsilon<T>()))
0062 return 1 / a;
0063 if(b == 1)
0064 return 1/a;
0065 else if(a == 1)
0066 return 1/b;
0067 else if(c < tools::epsilon<T>())
0068 {
0069 result = c / a;
0070 result /= b;
0071 return result;
0072 }
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 if(a < b)
0098 {
0099 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0100 }
0101
0102
0103 T agh = static_cast<T>(a + Lanczos::g() - 0.5f);
0104 T bgh = static_cast<T>(b + Lanczos::g() - 0.5f);
0105 T cgh = static_cast<T>(c + Lanczos::g() - 0.5f);
0106 result = Lanczos::lanczos_sum_expG_scaled(a) * (Lanczos::lanczos_sum_expG_scaled(b) / Lanczos::lanczos_sum_expG_scaled(c));
0107 T ambh = a - 0.5f - b;
0108 if((fabs(b * ambh) < (cgh * 100)) && (a > 100))
0109 {
0110
0111
0112 result *= exp(ambh * boost::math::log1p(-b / cgh, pol));
0113 }
0114 else
0115 {
0116 result *= pow(agh / cgh, a - T(0.5) - b);
0117 }
0118 if(cgh > 1e10f)
0119
0120 result *= pow((agh / cgh) * (bgh / cgh), b);
0121 else
0122 result *= pow((agh * bgh) / (cgh * cgh), b);
0123 result *= sqrt(boost::math::constants::e<T>() / bgh);
0124
0125
0126 result *= prefix;
0127
0128 return result;
0129 }
0130
0131
0132
0133
0134
0135 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0136 template <class T, class Policy>
0137 BOOST_MATH_GPU_ENABLED T beta_imp(T a, T b, const lanczos::undefined_lanczos& l, const Policy& pol)
0138 {
0139 BOOST_MATH_STD_USING
0140
0141 if(a <= 0)
0142 return policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got a=%1%).", a, pol);
0143 if(b <= 0)
0144 return policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got b=%1%).", b, pol);
0145
0146 const T c = a + b;
0147
0148
0149 if ((c == a) && (b < tools::epsilon<T>()))
0150 return 1 / b;
0151 else if ((c == b) && (a < tools::epsilon<T>()))
0152 return 1 / a;
0153 if (b == 1)
0154 return 1 / a;
0155 else if (a == 1)
0156 return 1 / b;
0157 else if (c < tools::epsilon<T>())
0158 {
0159 T result = c / a;
0160 result /= b;
0161 return result;
0162 }
0163
0164
0165 const T min_sterling = minimum_argument_for_bernoulli_recursion<T>();
0166
0167 long shift_a = 0;
0168 long shift_b = 0;
0169
0170 if(a < min_sterling)
0171 shift_a = 1 + ltrunc(min_sterling - a);
0172 if(b < min_sterling)
0173 shift_b = 1 + ltrunc(min_sterling - b);
0174 long shift_c = shift_a + shift_b;
0175
0176 if ((shift_a == 0) && (shift_b == 0))
0177 {
0178 return pow(a / c, a) * pow(b / c, b) * scaled_tgamma_no_lanczos(a, pol) * scaled_tgamma_no_lanczos(b, pol) / scaled_tgamma_no_lanczos(c, pol);
0179 }
0180 else if ((a < 1) && (b < 1))
0181 {
0182 return boost::math::tgamma(a, pol) * (boost::math::tgamma(b, pol) / boost::math::tgamma(c));
0183 }
0184 else if(a < 1)
0185 return boost::math::tgamma(a, pol) * boost::math::tgamma_delta_ratio(b, a, pol);
0186 else if(b < 1)
0187 return boost::math::tgamma(b, pol) * boost::math::tgamma_delta_ratio(a, b, pol);
0188 else
0189 {
0190 T result = beta_imp(T(a + shift_a), T(b + shift_b), l, pol);
0191
0192
0193
0194 for (long i = 0; i < shift_c; ++i)
0195 {
0196 result *= c + i;
0197 if (i < shift_a)
0198 result /= a + i;
0199 if (i < shift_b)
0200 result /= b + i;
0201 }
0202 return result;
0203 }
0204
0205 }
0206 #endif
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 template <class T, class Lanczos, class Policy>
0220 BOOST_MATH_GPU_ENABLED T ibeta_power_terms(T a,
0221 T b,
0222 T x,
0223 T y,
0224 const Lanczos&,
0225 bool normalised,
0226 const Policy& pol,
0227 T prefix = 1,
0228 const char* function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)")
0229 {
0230 BOOST_MATH_STD_USING
0231
0232 if(!normalised)
0233 {
0234
0235 return pow(x, a) * pow(y, b);
0236 }
0237
0238 T result;
0239
0240 T c = a + b;
0241
0242
0243 T agh = static_cast<T>(a + Lanczos::g() - 0.5f);
0244 T bgh = static_cast<T>(b + Lanczos::g() - 0.5f);
0245 T cgh = static_cast<T>(c + Lanczos::g() - 0.5f);
0246 if ((a < tools::min_value<T>()) || (b < tools::min_value<T>()))
0247 result = 0;
0248 else
0249 result = Lanczos::lanczos_sum_expG_scaled(c) / (Lanczos::lanczos_sum_expG_scaled(a) * Lanczos::lanczos_sum_expG_scaled(b));
0250 result *= prefix;
0251
0252 result *= sqrt(bgh / boost::math::constants::e<T>());
0253 result *= sqrt(agh / cgh);
0254
0255
0256 T l1 = (x * b - y * agh) / agh;
0257 T l2 = (y * a - x * bgh) / bgh;
0258 if((BOOST_MATH_GPU_SAFE_MIN(fabs(l1), fabs(l2)) < 0.2))
0259 {
0260
0261
0262 if((l1 * l2 > 0) || (BOOST_MATH_GPU_SAFE_MIN(a, b) < 1))
0263 {
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 if(fabs(l1) < 0.1)
0278 {
0279 result *= exp(a * boost::math::log1p(l1, pol));
0280 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0281 }
0282 else
0283 {
0284 result *= pow((x * cgh) / agh, a);
0285 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0286 }
0287 if(fabs(l2) < 0.1)
0288 {
0289 result *= exp(b * boost::math::log1p(l2, pol));
0290 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0291 }
0292 else
0293 {
0294 result *= pow((y * cgh) / bgh, b);
0295 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0296 }
0297 }
0298 else if(BOOST_MATH_GPU_SAFE_MAX(fabs(l1), fabs(l2)) < 0.5)
0299 {
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319 bool small_a = a < b;
0320 T ratio = b / a;
0321 if((small_a && (ratio * l2 < 0.1)) || (!small_a && (l1 / ratio > 0.1)))
0322 {
0323 T l3 = boost::math::expm1(ratio * boost::math::log1p(l2, pol), pol);
0324 l3 = l1 + l3 + l3 * l1;
0325 l3 = a * boost::math::log1p(l3, pol);
0326 result *= exp(l3);
0327 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0328 }
0329 else
0330 {
0331 T l3 = boost::math::expm1(boost::math::log1p(l1, pol) / ratio, pol);
0332 l3 = l2 + l3 + l3 * l2;
0333 l3 = b * boost::math::log1p(l3, pol);
0334 result *= exp(l3);
0335 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0336 }
0337 }
0338 else if(fabs(l1) < fabs(l2))
0339 {
0340
0341 T l = a * boost::math::log1p(l1, pol)
0342 + b * log((y * cgh) / bgh);
0343 if((l <= tools::log_min_value<T>()) || (l >= tools::log_max_value<T>()))
0344 {
0345 l += log(result);
0346 if(l >= tools::log_max_value<T>())
0347 return policies::raise_overflow_error<T>(function, nullptr, pol);
0348 result = exp(l);
0349 }
0350 else
0351 result *= exp(l);
0352 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0353 }
0354 else
0355 {
0356
0357 T l = b * boost::math::log1p(l2, pol)
0358 + a * log((x * cgh) / agh);
0359 if((l <= tools::log_min_value<T>()) || (l >= tools::log_max_value<T>()))
0360 {
0361 l += log(result);
0362 if(l >= tools::log_max_value<T>())
0363 return policies::raise_overflow_error<T>(function, nullptr, pol);
0364 result = exp(l);
0365 }
0366 else
0367 result *= exp(l);
0368 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0369 }
0370 }
0371 else
0372 {
0373
0374 T b1 = (x * cgh) / agh;
0375 T b2 = (y * cgh) / bgh;
0376 l1 = a * log(b1);
0377 l2 = b * log(b2);
0378 BOOST_MATH_INSTRUMENT_VARIABLE(b1);
0379 BOOST_MATH_INSTRUMENT_VARIABLE(b2);
0380 BOOST_MATH_INSTRUMENT_VARIABLE(l1);
0381 BOOST_MATH_INSTRUMENT_VARIABLE(l2);
0382 if((l1 >= tools::log_max_value<T>())
0383 || (l1 <= tools::log_min_value<T>())
0384 || (l2 >= tools::log_max_value<T>())
0385 || (l2 <= tools::log_min_value<T>())
0386 )
0387 {
0388
0389 if(a < b)
0390 {
0391 T p1 = pow(b2, b / a);
0392 T l3 = (b1 != 0) && (p1 != 0) ? (a * (log(b1) + log(p1))) : tools::max_value<T>();
0393 if((l3 < tools::log_max_value<T>())
0394 && (l3 > tools::log_min_value<T>()))
0395 {
0396 result *= pow(p1 * b1, a);
0397 }
0398 else
0399 {
0400 l2 += l1 + log(result);
0401 if(l2 >= tools::log_max_value<T>())
0402 return policies::raise_overflow_error<T>(function, nullptr, pol);
0403 result = exp(l2);
0404 }
0405 }
0406 else
0407 {
0408
0409 T p1 = (b1 < 1) && (b < 1) && (tools::max_value<T>() * b < a) ? static_cast<T>(0) : static_cast<T>(pow(b1, a / b));
0410 T l3 = (p1 != 0) && (b2 != 0) ? (log(p1) + log(b2)) * b : tools::max_value<T>();
0411 if((l3 < tools::log_max_value<T>())
0412 && (l3 > tools::log_min_value<T>()))
0413 {
0414 result *= pow(p1 * b2, b);
0415 }
0416 else if(result != 0)
0417 {
0418 l2 += l1 + log(result);
0419 if(l2 >= tools::log_max_value<T>())
0420 return policies::raise_overflow_error<T>(function, nullptr, pol);
0421 result = exp(l2);
0422 }
0423 }
0424 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0425 }
0426 else
0427 {
0428
0429 result *= pow(b1, a) * pow(b2, b);
0430 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0431 }
0432 }
0433
0434 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0435
0436 if (0 == result)
0437 {
0438 if ((a > 1) && (x == 0))
0439 return result;
0440 if ((b > 1) && (y == 0))
0441 return result;
0442 return boost::math::policies::raise_underflow_error<T>(function, nullptr, pol);
0443 }
0444
0445 return result;
0446 }
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0461 template <class T, class Policy>
0462 BOOST_MATH_GPU_ENABLED T ibeta_power_terms(T a,
0463 T b,
0464 T x,
0465 T y,
0466 const boost::math::lanczos::undefined_lanczos& l,
0467 bool normalised,
0468 const Policy& pol,
0469 T prefix = 1,
0470 const char* = "boost::math::ibeta<%1%>(%1%, %1%, %1%)")
0471 {
0472 BOOST_MATH_STD_USING
0473
0474 if(!normalised)
0475 {
0476 return prefix * pow(x, a) * pow(y, b);
0477 }
0478
0479 T c = a + b;
0480
0481 const T min_sterling = minimum_argument_for_bernoulli_recursion<T>();
0482
0483 long shift_a = 0;
0484 long shift_b = 0;
0485
0486 if (a < min_sterling)
0487 shift_a = 1 + ltrunc(min_sterling - a);
0488 if (b < min_sterling)
0489 shift_b = 1 + ltrunc(min_sterling - b);
0490
0491 if ((shift_a == 0) && (shift_b == 0))
0492 {
0493 T power1, power2;
0494 bool need_logs = false;
0495 if (a < b)
0496 {
0497 BOOST_MATH_IF_CONSTEXPR(boost::math::numeric_limits<T>::has_infinity)
0498 {
0499 power1 = pow((x * y * c * c) / (a * b), a);
0500 power2 = pow((y * c) / b, b - a);
0501 }
0502 else
0503 {
0504
0505 T l1 = log((x * y * c * c) / (a * b));
0506 T l2 = log((y * c) / b);
0507 if ((l1 * a > tools::log_min_value<T>()) && (l1 * a < tools::log_max_value<T>()) && (l2 * (b - a) < tools::log_max_value<T>()) && (l2 * (b - a) > tools::log_min_value<T>()))
0508 {
0509 power1 = pow((x * y * c * c) / (a * b), a);
0510 power2 = pow((y * c) / b, b - a);
0511 }
0512 else
0513 {
0514 need_logs = true;
0515 }
0516 }
0517 }
0518 else
0519 {
0520 BOOST_MATH_IF_CONSTEXPR(boost::math::numeric_limits<T>::has_infinity)
0521 {
0522 power1 = pow((x * y * c * c) / (a * b), b);
0523 power2 = pow((x * c) / a, a - b);
0524 }
0525 else
0526 {
0527
0528 T l1 = log((x * y * c * c) / (a * b)) * b;
0529 T l2 = log((x * c) / a) * (a - b);
0530 if ((l1 * a > tools::log_min_value<T>()) && (l1 * a < tools::log_max_value<T>()) && (l2 * (b - a) < tools::log_max_value<T>()) && (l2 * (b - a) > tools::log_min_value<T>()))
0531 {
0532 power1 = pow((x * y * c * c) / (a * b), b);
0533 power2 = pow((x * c) / a, a - b);
0534 }
0535 else
0536 need_logs = true;
0537 }
0538 }
0539 BOOST_MATH_IF_CONSTEXPR(boost::math::numeric_limits<T>::has_infinity)
0540 {
0541 if (!(boost::math::isnormal)(power1) || !(boost::math::isnormal)(power2))
0542 {
0543 need_logs = true;
0544 }
0545 }
0546 if (need_logs)
0547 {
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 T xc_a = x * c / a;
0577 T yc_b = y * c / b;
0578 if ((x == 1) || (y == 1) || (fabs(xc_a - 1) > 0.25) || (fabs(yc_b - 1) > 0.25))
0579 {
0580
0581 power1 = exp(log(xc_a) * a + log(yc_b) * b);
0582 power2 = 1;
0583 }
0584 else if (b > a)
0585 {
0586 T p = boost::math::expm1((b / a) * boost::math::log1p((y * a - x * b) / b));
0587 power1 = exp(a * boost::math::log1p((x * b - y * a) / a + p * (x * c / a)));
0588 power2 = 1;
0589 }
0590 else
0591 {
0592 T p = boost::math::expm1((a / b) * boost::math::log1p((x * b - y * a) / a));
0593 power1 = exp(b * boost::math::log1p((y * a - x * b) / b + p * (y * c / b)));
0594 power2 = 1;
0595 }
0596 }
0597 return prefix * power1 * power2 * scaled_tgamma_no_lanczos(c, pol) / (scaled_tgamma_no_lanczos(a, pol) * scaled_tgamma_no_lanczos(b, pol));
0598 }
0599
0600 T power1 = pow(x, a);
0601 T power2 = pow(y, b);
0602 T bet = beta_imp(a, b, l, pol);
0603
0604 if(!(boost::math::isnormal)(power1) || !(boost::math::isnormal)(power2) || !(boost::math::isnormal)(bet))
0605 {
0606 int shift_c = shift_a + shift_b;
0607 T result = ibeta_power_terms(T(a + shift_a), T(b + shift_b), x, y, l, normalised, pol, prefix);
0608 if ((boost::math::isnormal)(result))
0609 {
0610 for (int i = 0; i < shift_c; ++i)
0611 {
0612 result /= c + i;
0613 if (i < shift_a)
0614 {
0615 result *= a + i;
0616 result /= x;
0617 }
0618 if (i < shift_b)
0619 {
0620 result *= b + i;
0621 result /= y;
0622 }
0623 }
0624 return prefix * result;
0625 }
0626 else
0627 {
0628 T log_result = log(x) * a + log(y) * b + log(prefix);
0629 if ((boost::math::isnormal)(bet))
0630 log_result -= log(bet);
0631 else
0632 log_result += boost::math::lgamma(c, pol) - boost::math::lgamma(a, pol) - boost::math::lgamma(b, pol);
0633 return exp(log_result);
0634 }
0635 }
0636 return prefix * power1 * (power2 / bet);
0637 }
0638
0639 #endif
0640
0641
0642
0643 template <class T>
0644 struct ibeta_series_t
0645 {
0646 typedef T result_type;
0647 BOOST_MATH_GPU_ENABLED ibeta_series_t(T a_, T b_, T x_, T mult) : result(mult), x(x_), apn(a_), poch(1-b_), n(1) {}
0648 BOOST_MATH_GPU_ENABLED T operator()()
0649 {
0650 T r = result / apn;
0651 apn += 1;
0652 result *= poch * x / n;
0653 ++n;
0654 poch += 1;
0655 return r;
0656 }
0657 private:
0658 T result, x, apn, poch;
0659 int n;
0660 };
0661
0662 template <class T, class Lanczos, class Policy>
0663 BOOST_MATH_GPU_ENABLED T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_derivative, T y, const Policy& pol)
0664 {
0665 BOOST_MATH_STD_USING
0666
0667 T result;
0668
0669 BOOST_MATH_ASSERT((p_derivative == 0) || normalised);
0670
0671 if(normalised)
0672 {
0673 T c = a + b;
0674
0675
0676 T agh = static_cast<T>(a + Lanczos::g() - 0.5f);
0677 T bgh = static_cast<T>(b + Lanczos::g() - 0.5f);
0678 T cgh = static_cast<T>(c + Lanczos::g() - 0.5f);
0679 if ((a < tools::min_value<T>()) || (b < tools::min_value<T>()))
0680 result = 0;
0681 else
0682 result = Lanczos::lanczos_sum_expG_scaled(c) / (Lanczos::lanczos_sum_expG_scaled(a) * Lanczos::lanczos_sum_expG_scaled(b));
0683
0684 if (!(boost::math::isfinite)(result))
0685 result = 0;
0686
0687 T l1 = log(cgh / bgh) * (b - 0.5f);
0688 T l2 = log(x * cgh / agh) * a;
0689
0690
0691
0692 if((l1 > tools::log_min_value<T>())
0693 && (l1 < tools::log_max_value<T>())
0694 && (l2 > tools::log_min_value<T>())
0695 && (l2 < tools::log_max_value<T>()))
0696 {
0697 if(a * b < bgh * 10)
0698 result *= exp((b - 0.5f) * boost::math::log1p(a / bgh, pol));
0699 else
0700 result *= pow(cgh / bgh, T(b - T(0.5)));
0701 result *= pow(x * cgh / agh, a);
0702 result *= sqrt(agh / boost::math::constants::e<T>());
0703
0704 if(p_derivative)
0705 {
0706 *p_derivative = result * pow(y, b);
0707 BOOST_MATH_ASSERT(*p_derivative >= 0);
0708 }
0709 }
0710 else
0711 {
0712
0713
0714
0715 if (result != 0)
0716 {
0717 result = log(result) + l1 + l2 + (log(agh) - 1) / 2;
0718 if (p_derivative)
0719 *p_derivative = exp(result + b * log(y));
0720 result = exp(result);
0721 }
0722 }
0723 }
0724 else
0725 {
0726
0727 result = pow(x, a);
0728 }
0729 if(result < tools::min_value<T>())
0730 return s0;
0731 ibeta_series_t<T> s(a, b, x, result);
0732 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0733 result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, s0);
0734 policies::check_series_iterations<T>("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (with lanczos)", max_iter, pol);
0735 return result;
0736 }
0737
0738
0739
0740 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0741 template <class T, class Policy>
0742 BOOST_MATH_GPU_ENABLED T ibeta_series(T a, T b, T x, T s0, const boost::math::lanczos::undefined_lanczos& l, bool normalised, T* p_derivative, T y, const Policy& pol)
0743 {
0744 BOOST_MATH_STD_USING
0745
0746 T result;
0747 BOOST_MATH_ASSERT((p_derivative == 0) || normalised);
0748
0749 if(normalised)
0750 {
0751 const T min_sterling = minimum_argument_for_bernoulli_recursion<T>();
0752
0753 long shift_a = 0;
0754 long shift_b = 0;
0755
0756 if (a < min_sterling)
0757 shift_a = 1 + ltrunc(min_sterling - a);
0758 if (b < min_sterling)
0759 shift_b = 1 + ltrunc(min_sterling - b);
0760
0761 T c = a + b;
0762
0763 if ((shift_a == 0) && (shift_b == 0))
0764 {
0765 result = pow(x * c / a, a) * pow(c / b, b) * scaled_tgamma_no_lanczos(c, pol) / (scaled_tgamma_no_lanczos(a, pol) * scaled_tgamma_no_lanczos(b, pol));
0766 }
0767 else if ((a < 1) && (b > 1))
0768 result = pow(x, a) / (boost::math::tgamma(a, pol) * boost::math::tgamma_delta_ratio(b, a, pol));
0769 else
0770 {
0771 T power = pow(x, a);
0772 T bet = beta_imp(a, b, l, pol);
0773 if (!(boost::math::isnormal)(power) || !(boost::math::isnormal)(bet))
0774 {
0775 result = exp(a * log(x) + boost::math::lgamma(c, pol) - boost::math::lgamma(a, pol) - boost::math::lgamma(b, pol));
0776 }
0777 else
0778 result = power / bet;
0779 }
0780 if(p_derivative)
0781 {
0782 *p_derivative = result * pow(y, b);
0783 BOOST_MATH_ASSERT(*p_derivative >= 0);
0784 }
0785 }
0786 else
0787 {
0788
0789 result = pow(x, a);
0790 }
0791 if(result < tools::min_value<T>())
0792 return s0;
0793 ibeta_series_t<T> s(a, b, x, result);
0794 boost::math::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
0795 result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, s0);
0796 policies::check_series_iterations<T>("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (without lanczos)", max_iter, pol);
0797 return result;
0798 }
0799 #endif
0800
0801
0802
0803 template <class T>
0804 struct ibeta_fraction2_t
0805 {
0806 typedef boost::math::pair<T, T> result_type;
0807
0808 BOOST_MATH_GPU_ENABLED ibeta_fraction2_t(T a_, T b_, T x_, T y_) : a(a_), b(b_), x(x_), y(y_), m(0) {}
0809
0810 BOOST_MATH_GPU_ENABLED result_type operator()()
0811 {
0812 T aN = (a + m - 1) * (a + b + m - 1) * m * (b - m) * x * x;
0813 T denom = (a + 2 * m - 1);
0814 aN /= denom * denom;
0815
0816 T bN = static_cast<T>(m);
0817 bN += (m * (b - m) * x) / (a + 2*m - 1);
0818 bN += ((a + m) * (a * y - b * x + 1 + m *(2 - x))) / (a + 2*m + 1);
0819
0820 ++m;
0821
0822 return boost::math::make_pair(aN, bN);
0823 }
0824
0825 private:
0826 T a, b, x, y;
0827 int m;
0828 };
0829
0830
0831
0832 template <class T, class Policy>
0833 BOOST_MATH_GPU_ENABLED inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, T* p_derivative)
0834 {
0835 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
0836 BOOST_MATH_STD_USING
0837 T result = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol);
0838 if(p_derivative)
0839 {
0840 *p_derivative = result;
0841 BOOST_MATH_ASSERT(*p_derivative >= 0);
0842 }
0843 if(result == 0)
0844 return result;
0845
0846 ibeta_fraction2_t<T> f(a, b, x, y);
0847 T fract = boost::math::tools::continued_fraction_b(f, boost::math::policies::get_epsilon<T, Policy>());
0848 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
0849 BOOST_MATH_INSTRUMENT_VARIABLE(result);
0850 return result / fract;
0851 }
0852
0853
0854
0855 template <class T, class Policy>
0856 BOOST_MATH_GPU_ENABLED T ibeta_a_step(T a, T b, T x, T y, int k, const Policy& pol, bool normalised, T* p_derivative)
0857 {
0858 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
0859
0860 BOOST_MATH_INSTRUMENT_VARIABLE(k);
0861
0862 T prefix = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol);
0863 if(p_derivative)
0864 {
0865 *p_derivative = prefix;
0866 BOOST_MATH_ASSERT(*p_derivative >= 0);
0867 }
0868 prefix /= a;
0869 if(prefix == 0)
0870 return prefix;
0871 T sum = 1;
0872 T term = 1;
0873
0874 for(int i = 0; i < k-1; ++i)
0875 {
0876 term *= (a+b+i) * x / (a+i+1);
0877 sum += term;
0878 }
0879 prefix *= sum;
0880
0881 return prefix;
0882 }
0883
0884
0885
0886
0887
0888
0889
0890 template <class T>
0891 BOOST_MATH_GPU_ENABLED inline T rising_factorial_ratio(T a, T b, int k)
0892 {
0893
0894
0895
0896
0897
0898
0899
0900
0901 BOOST_MATH_INSTRUMENT_VARIABLE(k);
0902 BOOST_MATH_ASSERT(k > 0);
0903
0904 T result = 1;
0905 for(int i = 0; i < k; ++i)
0906 result *= (a+i) / (b+i);
0907 return result;
0908 }
0909
0910
0911
0912
0913
0914
0915
0916
0917 template <class T>
0918 struct Pn_size
0919 {
0920
0921
0922 #ifndef BOOST_MATH_HAS_NVRTC
0923 static constexpr unsigned value =
0924 ::boost::math::max_factorial<T>::value >= 100 ? 50
0925 : ::boost::math::max_factorial<T>::value >= ::boost::math::max_factorial<double>::value ? 30
0926 : ::boost::math::max_factorial<T>::value >= ::boost::math::max_factorial<float>::value ? 15 : 1;
0927 static_assert(::boost::math::max_factorial<T>::value >= ::boost::math::max_factorial<float>::value, "Type does not provide for 35-50 digits of accuracy.");
0928 #else
0929 static constexpr unsigned value = 0;
0930 #endif
0931 };
0932 template <>
0933 struct Pn_size<float>
0934 {
0935 static constexpr unsigned value = 15;
0936 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0937 static_assert(::boost::math::max_factorial<float>::value >= 30, "Type does not provide for 8-15 digits of accuracy.");
0938 #endif
0939 };
0940 template <>
0941 struct Pn_size<double>
0942 {
0943 static constexpr unsigned value = 30;
0944 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0945 static_assert(::boost::math::max_factorial<double>::value >= 60, "Type does not provide for 16-20 digits of accuracy.");
0946 #endif
0947 };
0948 template <>
0949 struct Pn_size<long double>
0950 {
0951 static constexpr unsigned value = 50;
0952 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0953 static_assert(::boost::math::max_factorial<long double>::value >= 100, "Type does not provide for ~35-50 digits of accuracy");
0954 #endif
0955 };
0956
0957 template <class T, class Policy>
0958 BOOST_MATH_GPU_ENABLED T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& pol, bool normalised)
0959 {
0960 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
0961 BOOST_MATH_STD_USING
0962
0963
0964
0965
0966
0967 T bm1 = b - 1;
0968 T t = a + bm1 / 2;
0969 T lx, u;
0970 if(y < 0.35)
0971 lx = boost::math::log1p(-y, pol);
0972 else
0973 lx = log(x);
0974 u = -t * lx;
0975
0976 T prefix;
0977 T h = regularised_gamma_prefix(b, u, pol, lanczos_type());
0978 if(h <= tools::min_value<T>())
0979 return s0;
0980 if(normalised)
0981 {
0982 prefix = h / boost::math::tgamma_delta_ratio(a, b, pol);
0983 prefix /= pow(t, b);
0984 }
0985 else
0986 {
0987 prefix = full_igamma_prefix(b, u, pol) / pow(t, b);
0988 }
0989 prefix *= mult;
0990
0991
0992
0993
0994
0995 T p[ ::boost::math::detail::Pn_size<T>::value ] = { 1 };
0996
0997
0998
0999 T j = boost::math::gamma_q(b, u, pol) / h;
1000
1001
1002
1003 T sum = s0 + prefix * j;
1004
1005 unsigned tnp1 = 1;
1006 T lx2 = lx / 2;
1007 lx2 *= lx2;
1008 T lxp = 1;
1009 T t4 = 4 * t * t;
1010 T b2n = b;
1011
1012 for(unsigned n = 1; n < sizeof(p)/sizeof(p[0]); ++n)
1013 {
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028 tnp1 += 2;
1029 p[n] = 0;
1030 T mbn = b - n;
1031 unsigned tmp1 = 3;
1032 for(unsigned m = 1; m < n; ++m)
1033 {
1034 mbn = m * b - n;
1035 p[n] += mbn * p[n-m] / boost::math::unchecked_factorial<T>(tmp1);
1036 tmp1 += 2;
1037 }
1038 p[n] /= n;
1039 p[n] += bm1 / boost::math::unchecked_factorial<T>(tnp1);
1040
1041
1042
1043 j = (b2n * (b2n + 1) * j + (u + b2n + 1) * lxp) / t4;
1044 lxp *= lx2;
1045 b2n += 2;
1046
1047
1048
1049 T r = prefix * p[n] * j;
1050 sum += r;
1051
1052 BOOST_MATH_ASSERT(tools::max_value<T>() * tools::epsilon<T>() > fabs(r));
1053 if(fabs(r / tools::epsilon<T>()) < fabs(sum))
1054 break;
1055 }
1056 return sum;
1057 }
1058
1059
1060
1061
1062
1063 template <class T, class Policy>
1064 BOOST_MATH_GPU_ENABLED T binomial_ccdf(T n, T k, T x, T y, const Policy& pol)
1065 {
1066 BOOST_MATH_STD_USING
1067
1068 T result = pow(x, n);
1069
1070 if(result > tools::min_value<T>())
1071 {
1072 T term = result;
1073 for(unsigned i = itrunc(T(n - 1)); i > k; --i)
1074 {
1075 term *= ((i + 1) * y) / ((n - i) * x);
1076 result += term;
1077 }
1078 }
1079 else
1080 {
1081
1082
1083 int start = itrunc(n * x);
1084 if(start <= k + 1)
1085 start = itrunc(k + 2);
1086 result = static_cast<T>(pow(x, T(start)) * pow(y, n - T(start)) * boost::math::binomial_coefficient<T>(itrunc(n), itrunc(start), pol));
1087 if(result == 0)
1088 {
1089
1090
1091
1092
1093
1094 for(unsigned i = start - 1; i > k; --i)
1095 {
1096 result += static_cast<T>(pow(x, static_cast<T>(i)) * pow(y, n - i) * boost::math::binomial_coefficient<T>(itrunc(n), itrunc(i), pol));
1097 }
1098
1099 }
1100 else
1101 {
1102 T term = result;
1103 T start_term = result;
1104 for(unsigned i = start - 1; i > k; --i)
1105 {
1106 term *= ((i + 1) * y) / ((n - i) * x);
1107 result += term;
1108 }
1109 term = start_term;
1110 for(unsigned i = start + 1; i <= n; ++i)
1111 {
1112 term *= (n - i + 1) * x / (i * y);
1113 result += term;
1114 }
1115 }
1116 }
1117
1118 return result;
1119 }
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129 template <class T, class Policy>
1130 BOOST_MATH_GPU_ENABLED T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_derivative)
1131 {
1132 constexpr auto function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)";
1133 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1134 BOOST_MATH_STD_USING
1135
1136 BOOST_MATH_INSTRUMENT_VARIABLE(a);
1137 BOOST_MATH_INSTRUMENT_VARIABLE(b);
1138 BOOST_MATH_INSTRUMENT_VARIABLE(x);
1139 BOOST_MATH_INSTRUMENT_VARIABLE(inv);
1140 BOOST_MATH_INSTRUMENT_VARIABLE(normalised);
1141
1142 bool invert = inv;
1143 T fract;
1144 T y = 1 - x;
1145
1146 BOOST_MATH_ASSERT((p_derivative == 0) || normalised);
1147
1148 if(!(boost::math::isfinite)(a))
1149 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be finite (got a=%1%).", a, pol);
1150 if(!(boost::math::isfinite)(b))
1151 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be finite (got b=%1%).", b, pol);
1152 if (!(0 <= x && x <= 1))
1153 return policies::raise_domain_error<T>(function, "The argument x to the incomplete beta function must be in [0,1] (got x=%1%).", x, pol);
1154
1155 if(p_derivative)
1156 *p_derivative = -1;
1157
1158 if(normalised)
1159 {
1160 if(a < 0)
1161 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be >= zero (got a=%1%).", a, pol);
1162 if(b < 0)
1163 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be >= zero (got b=%1%).", b, pol);
1164
1165 if(a == 0)
1166 {
1167 if(b == 0)
1168 return policies::raise_domain_error<T>(function, "The arguments a and b to the incomplete beta function cannot both be zero, with x=%1%.", x, pol);
1169 if(b > 0)
1170 return static_cast<T>(inv ? 0 : 1);
1171 }
1172 else if(b == 0)
1173 {
1174 if(a > 0)
1175 return static_cast<T>(inv ? 1 : 0);
1176 }
1177 }
1178 else
1179 {
1180 if(a <= 0)
1181 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be greater than zero (got a=%1%).", a, pol);
1182 if(b <= 0)
1183 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be greater than zero (got b=%1%).", b, pol);
1184 }
1185
1186 if(x == 0)
1187 {
1188 if(p_derivative)
1189 {
1190 *p_derivative = (a == 1) ? (T)1 : (a < 1) ? T(tools::max_value<T>() / 2) : T(tools::min_value<T>() * 2);
1191 }
1192 return (invert ? (normalised ? T(1) : boost::math::beta(a, b, pol)) : T(0));
1193 }
1194 if(x == 1)
1195 {
1196 if(p_derivative)
1197 {
1198 *p_derivative = (b == 1) ? T(1) : (b < 1) ? T(tools::max_value<T>() / 2) : T(tools::min_value<T>() * 2);
1199 }
1200 return (invert == 0 ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0);
1201 }
1202 if((a == 0.5f) && (b == 0.5f))
1203 {
1204
1205 if(p_derivative)
1206 {
1207 *p_derivative = 1 / (constants::pi<T>() * sqrt(y * x));
1208 }
1209 T p = invert ? asin(sqrt(y)) / constants::half_pi<T>() : asin(sqrt(x)) / constants::half_pi<T>();
1210 if(!normalised)
1211 p *= constants::pi<T>();
1212 return p;
1213 }
1214 if(a == 1)
1215 {
1216 BOOST_MATH_GPU_SAFE_SWAP(a, b);
1217 BOOST_MATH_GPU_SAFE_SWAP(x, y);
1218 invert = !invert;
1219 }
1220 if(b == 1)
1221 {
1222
1223
1224
1225 if(a == 1)
1226 {
1227 if(p_derivative)
1228 *p_derivative = 1;
1229 return invert ? y : x;
1230 }
1231
1232 if(p_derivative)
1233 {
1234 *p_derivative = a * pow(x, a - 1);
1235 }
1236 T p;
1237 if(y < 0.5)
1238 p = invert ? T(-boost::math::expm1(a * boost::math::log1p(-y, pol), pol)) : T(exp(a * boost::math::log1p(-y, pol)));
1239 else
1240 p = invert ? T(-boost::math::powm1(x, a, pol)) : T(pow(x, a));
1241 if(!normalised)
1242 p /= a;
1243 return p;
1244 }
1245
1246 if(BOOST_MATH_GPU_SAFE_MIN(a, b) <= 1)
1247 {
1248 if(x > 0.5)
1249 {
1250 BOOST_MATH_GPU_SAFE_SWAP(a, b);
1251 BOOST_MATH_GPU_SAFE_SWAP(x, y);
1252 invert = !invert;
1253 BOOST_MATH_INSTRUMENT_VARIABLE(invert);
1254 }
1255 if(BOOST_MATH_GPU_SAFE_MAX(a, b) <= 1)
1256 {
1257
1258 if((a >= BOOST_MATH_GPU_SAFE_MIN(T(0.2), b)) || (pow(x, a) <= 0.9))
1259 {
1260 if(!invert)
1261 {
1262 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1263 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1264 }
1265 else
1266 {
1267 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1268 invert = false;
1269 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1270 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1271 }
1272 }
1273 else
1274 {
1275 BOOST_MATH_GPU_SAFE_SWAP(a, b);
1276 BOOST_MATH_GPU_SAFE_SWAP(x, y);
1277 invert = !invert;
1278 if(y >= 0.3)
1279 {
1280 if(!invert)
1281 {
1282 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1283 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1284 }
1285 else
1286 {
1287 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1288 invert = false;
1289 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1290 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1291 }
1292 }
1293 else
1294 {
1295
1296 T prefix;
1297 if(!normalised)
1298 {
1299 prefix = rising_factorial_ratio(T(a+b), a, 20);
1300 }
1301 else
1302 {
1303 prefix = 1;
1304 }
1305 fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative);
1306 if(!invert)
1307 {
1308 fract = beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
1309 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1310 }
1311 else
1312 {
1313 fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
1314 invert = false;
1315 fract = -beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
1316 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1317 }
1318 }
1319 }
1320 }
1321 else
1322 {
1323
1324 if((b <= 1) || ((x < 0.1) && (pow(b * x, a) <= 0.7)))
1325 {
1326 if(!invert)
1327 {
1328 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1329 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1330 }
1331 else
1332 {
1333 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1334 invert = false;
1335 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1336 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1337 }
1338 }
1339 else
1340 {
1341 BOOST_MATH_GPU_SAFE_SWAP(a, b);
1342 BOOST_MATH_GPU_SAFE_SWAP(x, y);
1343 invert = !invert;
1344
1345 if(y >= 0.3)
1346 {
1347 if(!invert)
1348 {
1349 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1350 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1351 }
1352 else
1353 {
1354 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1355 invert = false;
1356 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1357 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1358 }
1359 }
1360 else if(a >= 15)
1361 {
1362 if(!invert)
1363 {
1364 fract = beta_small_b_large_a_series(a, b, x, y, T(0), T(1), pol, normalised);
1365 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1366 }
1367 else
1368 {
1369 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1370 invert = false;
1371 fract = -beta_small_b_large_a_series(a, b, x, y, fract, T(1), pol, normalised);
1372 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1373 }
1374 }
1375 else
1376 {
1377
1378 T prefix;
1379 if(!normalised)
1380 {
1381 prefix = rising_factorial_ratio(T(a+b), a, 20);
1382 }
1383 else
1384 {
1385 prefix = 1;
1386 }
1387 fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative);
1388 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1389 if(!invert)
1390 {
1391 fract = beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
1392 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1393 }
1394 else
1395 {
1396 fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
1397 invert = false;
1398 fract = -beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
1399 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1400 }
1401 }
1402 }
1403 }
1404 }
1405 else
1406 {
1407
1408 T lambda;
1409 if(a < b)
1410 {
1411 lambda = a - (a + b) * x;
1412 }
1413 else
1414 {
1415 lambda = (a + b) * y - b;
1416 }
1417 if(lambda < 0)
1418 {
1419 BOOST_MATH_GPU_SAFE_SWAP(a, b);
1420 BOOST_MATH_GPU_SAFE_SWAP(x, y);
1421 invert = !invert;
1422 BOOST_MATH_INSTRUMENT_VARIABLE(invert);
1423 }
1424
1425 if(b < 40)
1426 {
1427 if((floor(a) == a) && (floor(b) == b) && (a < static_cast<T>((boost::math::numeric_limits<int>::max)() - 100)) && (y != 1))
1428 {
1429
1430 T k = a - 1;
1431 T n = b + k;
1432 fract = binomial_ccdf(n, k, x, y, pol);
1433 if(!normalised)
1434 fract *= boost::math::beta(a, b, pol);
1435 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1436 }
1437 else if(b * x <= 0.7)
1438 {
1439 if(!invert)
1440 {
1441 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1442 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1443 }
1444 else
1445 {
1446 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1447 invert = false;
1448 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1449 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1450 }
1451 }
1452 else if(a > 15)
1453 {
1454
1455 int n = itrunc(T(floor(b)), pol);
1456 if(n == b)
1457 --n;
1458 T bbar = b - n;
1459 T prefix;
1460 if(!normalised)
1461 {
1462 prefix = rising_factorial_ratio(T(a+bbar), bbar, n);
1463 }
1464 else
1465 {
1466 prefix = 1;
1467 }
1468 fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast<T*>(nullptr));
1469 fract = beta_small_b_large_a_series(a, bbar, x, y, fract, T(1), pol, normalised);
1470 fract /= prefix;
1471 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1472 }
1473 else if(normalised)
1474 {
1475
1476
1477
1478 int n = itrunc(T(floor(b)), pol);
1479 T bbar = b - n;
1480 if(bbar <= 0)
1481 {
1482 --n;
1483 bbar += 1;
1484 }
1485 fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast<T*>(nullptr));
1486 fract += ibeta_a_step(a, bbar, x, y, 20, pol, normalised, static_cast<T*>(nullptr));
1487 if(invert)
1488 fract -= 1;
1489 fract = beta_small_b_large_a_series(T(a+20), bbar, x, y, fract, T(1), pol, normalised);
1490 if(invert)
1491 {
1492 fract = -fract;
1493 invert = false;
1494 }
1495 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1496 }
1497 else
1498 {
1499 fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
1500 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1501 }
1502 }
1503 else
1504 {
1505 fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
1506 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1507 }
1508 }
1509 if(p_derivative)
1510 {
1511 if(*p_derivative < 0)
1512 {
1513 *p_derivative = ibeta_power_terms(a, b, x, y, lanczos_type(), true, pol);
1514 }
1515 T div = y * x;
1516
1517 if(*p_derivative != 0)
1518 {
1519 if((tools::max_value<T>() * div < *p_derivative))
1520 {
1521
1522 *p_derivative = tools::max_value<T>() / 2;
1523 }
1524 else
1525 {
1526 *p_derivative /= div;
1527 }
1528 }
1529 }
1530 return invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) - fract : fract;
1531 }
1532
1533 template <class T, class Policy>
1534 BOOST_MATH_GPU_ENABLED inline T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised)
1535 {
1536 return ibeta_imp(a, b, x, pol, inv, normalised, static_cast<T*>(nullptr));
1537 }
1538
1539 template <class T, class Policy>
1540 BOOST_MATH_GPU_ENABLED T ibeta_derivative_imp(T a, T b, T x, const Policy& pol)
1541 {
1542 constexpr auto function = "ibeta_derivative<%1%>(%1%,%1%,%1%)";
1543
1544
1545
1546 if (!(boost::math::isfinite)(a))
1547 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be finite (got a=%1%).", a, pol);
1548 if (!(boost::math::isfinite)(b))
1549 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be finite (got b=%1%).", b, pol);
1550 if (!(0 <= x && x <= 1))
1551 return policies::raise_domain_error<T>(function, "The argument x to the incomplete beta function must be in [0,1] (got x=%1%).", x, pol);
1552
1553 if(a <= 0)
1554 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be greater than zero (got a=%1%).", a, pol);
1555 if(b <= 0)
1556 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be greater than zero (got b=%1%).", b, pol);
1557
1558
1559
1560 if(x == 0)
1561 {
1562 return (a > 1) ? 0 :
1563 (a == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, nullptr, pol);
1564 }
1565 else if(x == 1)
1566 {
1567 return (b > 1) ? 0 :
1568 (b == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, nullptr, pol);
1569 }
1570
1571
1572
1573 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1574 T y = (1 - x) * x;
1575 T f1;
1576 if (!(boost::math::isinf)(1 / y))
1577 {
1578 f1 = ibeta_power_terms<T>(a, b, x, 1 - x, lanczos_type(), true, pol, 1 / y, function);
1579 }
1580 else
1581 {
1582 return (a > 1) ? 0 : (a == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, nullptr, pol);
1583 }
1584
1585 return f1;
1586 }
1587
1588
1589
1590 template <class RT1, class RT2, class Policy>
1591 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2>::type
1592 beta(RT1 a, RT2 b, const Policy&, const boost::math::true_type*)
1593 {
1594 BOOST_FPU_EXCEPTION_GUARD
1595 typedef typename tools::promote_args<RT1, RT2>::type result_type;
1596 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1597 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1598 typedef typename policies::normalise<
1599 Policy,
1600 policies::promote_float<false>,
1601 policies::promote_double<false>,
1602 policies::discrete_quantile<>,
1603 policies::assert_undefined<> >::type forwarding_policy;
1604
1605 return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::beta_imp(static_cast<value_type>(a), static_cast<value_type>(b), evaluation_type(), forwarding_policy()), "boost::math::beta<%1%>(%1%,%1%)");
1606 }
1607 template <class RT1, class RT2, class RT3>
1608 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1609 beta(RT1 a, RT2 b, RT3 x, const boost::math::false_type*)
1610 {
1611 return boost::math::beta(a, b, x, policies::policy<>());
1612 }
1613 }
1614
1615
1616
1617
1618
1619
1620 template <class RT1, class RT2, class A>
1621 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, A>::type
1622 beta(RT1 a, RT2 b, A arg)
1623 {
1624 using tag = typename policies::is_policy<A>::type;
1625 using ReturnType = tools::promote_args_t<RT1, RT2, A>;
1626 return static_cast<ReturnType>(boost::math::detail::beta(a, b, arg, static_cast<tag*>(nullptr)));
1627 }
1628
1629 template <class RT1, class RT2>
1630 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2>::type
1631 beta(RT1 a, RT2 b)
1632 {
1633 return boost::math::beta(a, b, policies::policy<>());
1634 }
1635
1636 template <class RT1, class RT2, class RT3, class Policy>
1637 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1638 beta(RT1 a, RT2 b, RT3 x, const Policy&)
1639 {
1640 BOOST_FPU_EXCEPTION_GUARD
1641 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1642 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1643 typedef typename policies::normalise<
1644 Policy,
1645 policies::promote_float<false>,
1646 policies::promote_double<false>,
1647 policies::discrete_quantile<>,
1648 policies::assert_undefined<> >::type forwarding_policy;
1649
1650 return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), false, false), "boost::math::beta<%1%>(%1%,%1%,%1%)");
1651 }
1652
1653 template <class RT1, class RT2, class RT3, class Policy>
1654 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1655 betac(RT1 a, RT2 b, RT3 x, const Policy&)
1656 {
1657 BOOST_FPU_EXCEPTION_GUARD
1658 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1659 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1660 typedef typename policies::normalise<
1661 Policy,
1662 policies::promote_float<false>,
1663 policies::promote_double<false>,
1664 policies::discrete_quantile<>,
1665 policies::assert_undefined<> >::type forwarding_policy;
1666
1667 return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), true, false), "boost::math::betac<%1%>(%1%,%1%,%1%)");
1668 }
1669 template <class RT1, class RT2, class RT3>
1670 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1671 betac(RT1 a, RT2 b, RT3 x)
1672 {
1673 return boost::math::betac(a, b, x, policies::policy<>());
1674 }
1675
1676 template <class RT1, class RT2, class RT3, class Policy>
1677 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1678 ibeta(RT1 a, RT2 b, RT3 x, const Policy&)
1679 {
1680 BOOST_FPU_EXCEPTION_GUARD
1681 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1682 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1683 typedef typename policies::normalise<
1684 Policy,
1685 policies::promote_float<false>,
1686 policies::promote_double<false>,
1687 policies::discrete_quantile<>,
1688 policies::assert_undefined<> >::type forwarding_policy;
1689
1690 return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), false, true), "boost::math::ibeta<%1%>(%1%,%1%,%1%)");
1691 }
1692 template <class RT1, class RT2, class RT3>
1693 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1694 ibeta(RT1 a, RT2 b, RT3 x)
1695 {
1696 return boost::math::ibeta(a, b, x, policies::policy<>());
1697 }
1698
1699 template <class RT1, class RT2, class RT3, class Policy>
1700 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1701 ibetac(RT1 a, RT2 b, RT3 x, const Policy&)
1702 {
1703 BOOST_FPU_EXCEPTION_GUARD
1704 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1705 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1706 typedef typename policies::normalise<
1707 Policy,
1708 policies::promote_float<false>,
1709 policies::promote_double<false>,
1710 policies::discrete_quantile<>,
1711 policies::assert_undefined<> >::type forwarding_policy;
1712
1713 return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), true, true), "boost::math::ibetac<%1%>(%1%,%1%,%1%)");
1714 }
1715 template <class RT1, class RT2, class RT3>
1716 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1717 ibetac(RT1 a, RT2 b, RT3 x)
1718 {
1719 return boost::math::ibetac(a, b, x, policies::policy<>());
1720 }
1721
1722 template <class RT1, class RT2, class RT3, class Policy>
1723 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1724 ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy&)
1725 {
1726 BOOST_FPU_EXCEPTION_GUARD
1727 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1728 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1729 typedef typename policies::normalise<
1730 Policy,
1731 policies::promote_float<false>,
1732 policies::promote_double<false>,
1733 policies::discrete_quantile<>,
1734 policies::assert_undefined<> >::type forwarding_policy;
1735
1736 return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_derivative_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy()), "boost::math::ibeta_derivative<%1%>(%1%,%1%,%1%)");
1737 }
1738 template <class RT1, class RT2, class RT3>
1739 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1740 ibeta_derivative(RT1 a, RT2 b, RT3 x)
1741 {
1742 return boost::math::ibeta_derivative(a, b, x, policies::policy<>());
1743 }
1744
1745 }
1746 }
1747
1748 #include <boost/math/special_functions/detail/ibeta_inverse.hpp>
1749 #include <boost/math/special_functions/detail/ibeta_inv_ab.hpp>
1750
1751 #endif