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