File indexing completed on 2025-01-18 09:40:10
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_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_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_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 if(k == 0)
0885 return 1;
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 if(r > 1)
1024 {
1025 if(fabs(r) < fabs(tools::epsilon<T>() * sum))
1026 break;
1027 }
1028 else
1029 {
1030 if(fabs(r / tools::epsilon<T>()) < fabs(sum))
1031 break;
1032 }
1033 }
1034 return sum;
1035 }
1036
1037
1038
1039
1040
1041 template <class T, class Policy>
1042 T binomial_ccdf(T n, T k, T x, T y, const Policy& pol)
1043 {
1044 BOOST_MATH_STD_USING
1045
1046 T result = pow(x, n);
1047
1048 if(result > tools::min_value<T>())
1049 {
1050 T term = result;
1051 for(unsigned i = itrunc(T(n - 1)); i > k; --i)
1052 {
1053 term *= ((i + 1) * y) / ((n - i) * x);
1054 result += term;
1055 }
1056 }
1057 else
1058 {
1059
1060
1061 int start = itrunc(n * x);
1062 if(start <= k + 1)
1063 start = itrunc(k + 2);
1064 result = static_cast<T>(pow(x, T(start)) * pow(y, n - T(start)) * boost::math::binomial_coefficient<T>(itrunc(n), itrunc(start), pol));
1065 if(result == 0)
1066 {
1067
1068
1069 for(unsigned i = start - 1; i > k; --i)
1070 {
1071 result += static_cast<T>(pow(x, static_cast<T>(i)) * pow(y, n - i) * boost::math::binomial_coefficient<T>(itrunc(n), itrunc(i), pol));
1072 }
1073 }
1074 else
1075 {
1076 T term = result;
1077 T start_term = result;
1078 for(unsigned i = start - 1; i > k; --i)
1079 {
1080 term *= ((i + 1) * y) / ((n - i) * x);
1081 result += term;
1082 }
1083 term = start_term;
1084 for(unsigned i = start + 1; i <= n; ++i)
1085 {
1086 term *= (n - i + 1) * x / (i * y);
1087 result += term;
1088 }
1089 }
1090 }
1091
1092 return result;
1093 }
1094
1095
1096
1097
1098
1099
1100
1101
1102 template <class T, class Policy>
1103 T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_derivative)
1104 {
1105 static const char* function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)";
1106 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1107 BOOST_MATH_STD_USING
1108
1109 BOOST_MATH_INSTRUMENT_VARIABLE(a);
1110 BOOST_MATH_INSTRUMENT_VARIABLE(b);
1111 BOOST_MATH_INSTRUMENT_VARIABLE(x);
1112 BOOST_MATH_INSTRUMENT_VARIABLE(inv);
1113 BOOST_MATH_INSTRUMENT_VARIABLE(normalised);
1114
1115 bool invert = inv;
1116 T fract;
1117 T y = 1 - x;
1118
1119 BOOST_MATH_ASSERT((p_derivative == 0) || normalised);
1120
1121 if(!(boost::math::isfinite)(a))
1122 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be finite (got a=%1%).", a, pol);
1123 if(!(boost::math::isfinite)(b))
1124 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be finite (got b=%1%).", b, pol);
1125 if (!(0 <= x && x <= 1))
1126 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);
1127
1128 if(p_derivative)
1129 *p_derivative = -1;
1130
1131 if(normalised)
1132 {
1133 if(a < 0)
1134 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be >= zero (got a=%1%).", a, pol);
1135 if(b < 0)
1136 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be >= zero (got b=%1%).", b, pol);
1137
1138 if(a == 0)
1139 {
1140 if(b == 0)
1141 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);
1142 if(b > 0)
1143 return static_cast<T>(inv ? 0 : 1);
1144 }
1145 else if(b == 0)
1146 {
1147 if(a > 0)
1148 return static_cast<T>(inv ? 1 : 0);
1149 }
1150 }
1151 else
1152 {
1153 if(a <= 0)
1154 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);
1155 if(b <= 0)
1156 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);
1157 }
1158
1159 if(x == 0)
1160 {
1161 if(p_derivative)
1162 {
1163 *p_derivative = (a == 1) ? (T)1 : (a < 1) ? T(tools::max_value<T>() / 2) : T(tools::min_value<T>() * 2);
1164 }
1165 return (invert ? (normalised ? T(1) : boost::math::beta(a, b, pol)) : T(0));
1166 }
1167 if(x == 1)
1168 {
1169 if(p_derivative)
1170 {
1171 *p_derivative = (b == 1) ? T(1) : (b < 1) ? T(tools::max_value<T>() / 2) : T(tools::min_value<T>() * 2);
1172 }
1173 return (invert == 0 ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0);
1174 }
1175 if((a == 0.5f) && (b == 0.5f))
1176 {
1177
1178 if(p_derivative)
1179 {
1180 *p_derivative = 1 / constants::pi<T>() * sqrt(y * x);
1181 }
1182 T p = invert ? asin(sqrt(y)) / constants::half_pi<T>() : asin(sqrt(x)) / constants::half_pi<T>();
1183 if(!normalised)
1184 p *= constants::pi<T>();
1185 return p;
1186 }
1187 if(a == 1)
1188 {
1189 std::swap(a, b);
1190 std::swap(x, y);
1191 invert = !invert;
1192 }
1193 if(b == 1)
1194 {
1195
1196
1197
1198 if(a == 1)
1199 {
1200 if(p_derivative)
1201 *p_derivative = 1;
1202 return invert ? y : x;
1203 }
1204
1205 if(p_derivative)
1206 {
1207 *p_derivative = a * pow(x, a - 1);
1208 }
1209 T p;
1210 if(y < 0.5)
1211 p = invert ? T(-boost::math::expm1(a * boost::math::log1p(-y, pol), pol)) : T(exp(a * boost::math::log1p(-y, pol)));
1212 else
1213 p = invert ? T(-boost::math::powm1(x, a, pol)) : T(pow(x, a));
1214 if(!normalised)
1215 p /= a;
1216 return p;
1217 }
1218
1219 if((std::min)(a, b) <= 1)
1220 {
1221 if(x > 0.5)
1222 {
1223 std::swap(a, b);
1224 std::swap(x, y);
1225 invert = !invert;
1226 BOOST_MATH_INSTRUMENT_VARIABLE(invert);
1227 }
1228 if((std::max)(a, b) <= 1)
1229 {
1230
1231 if((a >= (std::min)(T(0.2), b)) || (pow(x, a) <= 0.9))
1232 {
1233 if(!invert)
1234 {
1235 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1236 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1237 }
1238 else
1239 {
1240 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1241 invert = false;
1242 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1243 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1244 }
1245 }
1246 else
1247 {
1248 std::swap(a, b);
1249 std::swap(x, y);
1250 invert = !invert;
1251 if(y >= 0.3)
1252 {
1253 if(!invert)
1254 {
1255 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1256 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1257 }
1258 else
1259 {
1260 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1261 invert = false;
1262 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1263 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1264 }
1265 }
1266 else
1267 {
1268
1269 T prefix;
1270 if(!normalised)
1271 {
1272 prefix = rising_factorial_ratio(T(a+b), a, 20);
1273 }
1274 else
1275 {
1276 prefix = 1;
1277 }
1278 fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative);
1279 if(!invert)
1280 {
1281 fract = beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
1282 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1283 }
1284 else
1285 {
1286 fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
1287 invert = false;
1288 fract = -beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
1289 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1290 }
1291 }
1292 }
1293 }
1294 else
1295 {
1296
1297 if((b <= 1) || ((x < 0.1) && (pow(b * x, a) <= 0.7)))
1298 {
1299 if(!invert)
1300 {
1301 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1302 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1303 }
1304 else
1305 {
1306 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1307 invert = false;
1308 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1309 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1310 }
1311 }
1312 else
1313 {
1314 std::swap(a, b);
1315 std::swap(x, y);
1316 invert = !invert;
1317
1318 if(y >= 0.3)
1319 {
1320 if(!invert)
1321 {
1322 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1323 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1324 }
1325 else
1326 {
1327 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1328 invert = false;
1329 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1330 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1331 }
1332 }
1333 else if(a >= 15)
1334 {
1335 if(!invert)
1336 {
1337 fract = beta_small_b_large_a_series(a, b, x, y, T(0), T(1), pol, normalised);
1338 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1339 }
1340 else
1341 {
1342 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1343 invert = false;
1344 fract = -beta_small_b_large_a_series(a, b, x, y, fract, T(1), pol, normalised);
1345 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1346 }
1347 }
1348 else
1349 {
1350
1351 T prefix;
1352 if(!normalised)
1353 {
1354 prefix = rising_factorial_ratio(T(a+b), a, 20);
1355 }
1356 else
1357 {
1358 prefix = 1;
1359 }
1360 fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative);
1361 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1362 if(!invert)
1363 {
1364 fract = beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, 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(T(a + 20), b, x, y, fract, prefix, pol, normalised);
1372 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1373 }
1374 }
1375 }
1376 }
1377 }
1378 else
1379 {
1380
1381 T lambda;
1382 if(a < b)
1383 {
1384 lambda = a - (a + b) * x;
1385 }
1386 else
1387 {
1388 lambda = (a + b) * y - b;
1389 }
1390 if(lambda < 0)
1391 {
1392 std::swap(a, b);
1393 std::swap(x, y);
1394 invert = !invert;
1395 BOOST_MATH_INSTRUMENT_VARIABLE(invert);
1396 }
1397
1398 if(b < 40)
1399 {
1400 if((floor(a) == a) && (floor(b) == b) && (a < static_cast<T>((std::numeric_limits<int>::max)() - 100)) && (y != 1))
1401 {
1402
1403 T k = a - 1;
1404 T n = b + k;
1405 fract = binomial_ccdf(n, k, x, y, pol);
1406 if(!normalised)
1407 fract *= boost::math::beta(a, b, pol);
1408 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1409 }
1410 else if(b * x <= 0.7)
1411 {
1412 if(!invert)
1413 {
1414 fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
1415 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1416 }
1417 else
1418 {
1419 fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
1420 invert = false;
1421 fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
1422 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1423 }
1424 }
1425 else if(a > 15)
1426 {
1427
1428 int n = itrunc(T(floor(b)), pol);
1429 if(n == b)
1430 --n;
1431 T bbar = b - n;
1432 T prefix;
1433 if(!normalised)
1434 {
1435 prefix = rising_factorial_ratio(T(a+bbar), bbar, n);
1436 }
1437 else
1438 {
1439 prefix = 1;
1440 }
1441 fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast<T*>(nullptr));
1442 fract = beta_small_b_large_a_series(a, bbar, x, y, fract, T(1), pol, normalised);
1443 fract /= prefix;
1444 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1445 }
1446 else if(normalised)
1447 {
1448
1449
1450
1451 int n = itrunc(T(floor(b)), pol);
1452 T bbar = b - n;
1453 if(bbar <= 0)
1454 {
1455 --n;
1456 bbar += 1;
1457 }
1458 fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast<T*>(nullptr));
1459 fract += ibeta_a_step(a, bbar, x, y, 20, pol, normalised, static_cast<T*>(nullptr));
1460 if(invert)
1461 fract -= 1;
1462 fract = beta_small_b_large_a_series(T(a+20), bbar, x, y, fract, T(1), pol, normalised);
1463 if(invert)
1464 {
1465 fract = -fract;
1466 invert = false;
1467 }
1468 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1469 }
1470 else
1471 {
1472 fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
1473 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1474 }
1475 }
1476 else
1477 {
1478 fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
1479 BOOST_MATH_INSTRUMENT_VARIABLE(fract);
1480 }
1481 }
1482 if(p_derivative)
1483 {
1484 if(*p_derivative < 0)
1485 {
1486 *p_derivative = ibeta_power_terms(a, b, x, y, lanczos_type(), true, pol);
1487 }
1488 T div = y * x;
1489
1490 if(*p_derivative != 0)
1491 {
1492 if((tools::max_value<T>() * div < *p_derivative))
1493 {
1494
1495 *p_derivative = tools::max_value<T>() / 2;
1496 }
1497 else
1498 {
1499 *p_derivative /= div;
1500 }
1501 }
1502 }
1503 return invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) - fract : fract;
1504 }
1505
1506 template <class T, class Policy>
1507 inline T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised)
1508 {
1509 return ibeta_imp(a, b, x, pol, inv, normalised, static_cast<T*>(nullptr));
1510 }
1511
1512 template <class T, class Policy>
1513 T ibeta_derivative_imp(T a, T b, T x, const Policy& pol)
1514 {
1515 static const char* function = "ibeta_derivative<%1%>(%1%,%1%,%1%)";
1516
1517
1518
1519 if (!(boost::math::isfinite)(a))
1520 return policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be finite (got a=%1%).", a, pol);
1521 if (!(boost::math::isfinite)(b))
1522 return policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be finite (got b=%1%).", b, pol);
1523 if (!(0 <= x && x <= 1))
1524 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);
1525
1526 if(a <= 0)
1527 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);
1528 if(b <= 0)
1529 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);
1530
1531
1532
1533 if(x == 0)
1534 {
1535 return (a > 1) ? 0 :
1536 (a == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, nullptr, pol);
1537 }
1538 else if(x == 1)
1539 {
1540 return (b > 1) ? 0 :
1541 (b == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, nullptr, pol);
1542 }
1543
1544
1545
1546 typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
1547 T y = (1 - x) * x;
1548 T f1;
1549 if (!(boost::math::isinf)(1 / y))
1550 {
1551 f1 = ibeta_power_terms<T>(a, b, x, 1 - x, lanczos_type(), true, pol, 1 / y, function);
1552 }
1553 else
1554 {
1555 return (a > 1) ? 0 : (a == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, nullptr, pol);
1556 }
1557
1558 return f1;
1559 }
1560
1561
1562
1563 template <class RT1, class RT2, class Policy>
1564 inline typename tools::promote_args<RT1, RT2>::type
1565 beta(RT1 a, RT2 b, const Policy&, const std::true_type*)
1566 {
1567 BOOST_FPU_EXCEPTION_GUARD
1568 typedef typename tools::promote_args<RT1, RT2>::type result_type;
1569 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1570 typedef typename lanczos::lanczos<value_type, Policy>::type evaluation_type;
1571 typedef typename policies::normalise<
1572 Policy,
1573 policies::promote_float<false>,
1574 policies::promote_double<false>,
1575 policies::discrete_quantile<>,
1576 policies::assert_undefined<> >::type forwarding_policy;
1577
1578 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%)");
1579 }
1580 template <class RT1, class RT2, class RT3>
1581 inline typename tools::promote_args<RT1, RT2, RT3>::type
1582 beta(RT1 a, RT2 b, RT3 x, const std::false_type*)
1583 {
1584 return boost::math::beta(a, b, x, policies::policy<>());
1585 }
1586 }
1587
1588
1589
1590
1591
1592
1593 template <class RT1, class RT2, class A>
1594 inline typename tools::promote_args<RT1, RT2, A>::type
1595 beta(RT1 a, RT2 b, A arg)
1596 {
1597 using tag = typename policies::is_policy<A>::type;
1598 using ReturnType = tools::promote_args_t<RT1, RT2, A>;
1599 return static_cast<ReturnType>(boost::math::detail::beta(a, b, arg, static_cast<tag*>(nullptr)));
1600 }
1601
1602 template <class RT1, class RT2>
1603 inline typename tools::promote_args<RT1, RT2>::type
1604 beta(RT1 a, RT2 b)
1605 {
1606 return boost::math::beta(a, b, policies::policy<>());
1607 }
1608
1609 template <class RT1, class RT2, class RT3, class Policy>
1610 inline typename tools::promote_args<RT1, RT2, RT3>::type
1611 beta(RT1 a, RT2 b, RT3 x, const Policy&)
1612 {
1613 BOOST_FPU_EXCEPTION_GUARD
1614 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1615 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1616 typedef typename policies::normalise<
1617 Policy,
1618 policies::promote_float<false>,
1619 policies::promote_double<false>,
1620 policies::discrete_quantile<>,
1621 policies::assert_undefined<> >::type forwarding_policy;
1622
1623 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%)");
1624 }
1625
1626 template <class RT1, class RT2, class RT3, class Policy>
1627 inline typename tools::promote_args<RT1, RT2, RT3>::type
1628 betac(RT1 a, RT2 b, RT3 x, const Policy&)
1629 {
1630 BOOST_FPU_EXCEPTION_GUARD
1631 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1632 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1633 typedef typename policies::normalise<
1634 Policy,
1635 policies::promote_float<false>,
1636 policies::promote_double<false>,
1637 policies::discrete_quantile<>,
1638 policies::assert_undefined<> >::type forwarding_policy;
1639
1640 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%)");
1641 }
1642 template <class RT1, class RT2, class RT3>
1643 inline typename tools::promote_args<RT1, RT2, RT3>::type
1644 betac(RT1 a, RT2 b, RT3 x)
1645 {
1646 return boost::math::betac(a, b, x, policies::policy<>());
1647 }
1648
1649 template <class RT1, class RT2, class RT3, class Policy>
1650 inline typename tools::promote_args<RT1, RT2, RT3>::type
1651 ibeta(RT1 a, RT2 b, RT3 x, const Policy&)
1652 {
1653 BOOST_FPU_EXCEPTION_GUARD
1654 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1655 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1656 typedef typename policies::normalise<
1657 Policy,
1658 policies::promote_float<false>,
1659 policies::promote_double<false>,
1660 policies::discrete_quantile<>,
1661 policies::assert_undefined<> >::type forwarding_policy;
1662
1663 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%)");
1664 }
1665 template <class RT1, class RT2, class RT3>
1666 inline typename tools::promote_args<RT1, RT2, RT3>::type
1667 ibeta(RT1 a, RT2 b, RT3 x)
1668 {
1669 return boost::math::ibeta(a, b, x, policies::policy<>());
1670 }
1671
1672 template <class RT1, class RT2, class RT3, class Policy>
1673 inline typename tools::promote_args<RT1, RT2, RT3>::type
1674 ibetac(RT1 a, RT2 b, RT3 x, const Policy&)
1675 {
1676 BOOST_FPU_EXCEPTION_GUARD
1677 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1678 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1679 typedef typename policies::normalise<
1680 Policy,
1681 policies::promote_float<false>,
1682 policies::promote_double<false>,
1683 policies::discrete_quantile<>,
1684 policies::assert_undefined<> >::type forwarding_policy;
1685
1686 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%)");
1687 }
1688 template <class RT1, class RT2, class RT3>
1689 inline typename tools::promote_args<RT1, RT2, RT3>::type
1690 ibetac(RT1 a, RT2 b, RT3 x)
1691 {
1692 return boost::math::ibetac(a, b, x, policies::policy<>());
1693 }
1694
1695 template <class RT1, class RT2, class RT3, class Policy>
1696 inline typename tools::promote_args<RT1, RT2, RT3>::type
1697 ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy&)
1698 {
1699 BOOST_FPU_EXCEPTION_GUARD
1700 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1701 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1702 typedef typename policies::normalise<
1703 Policy,
1704 policies::promote_float<false>,
1705 policies::promote_double<false>,
1706 policies::discrete_quantile<>,
1707 policies::assert_undefined<> >::type forwarding_policy;
1708
1709 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%)");
1710 }
1711 template <class RT1, class RT2, class RT3>
1712 inline typename tools::promote_args<RT1, RT2, RT3>::type
1713 ibeta_derivative(RT1 a, RT2 b, RT3 x)
1714 {
1715 return boost::math::ibeta_derivative(a, b, x, policies::policy<>());
1716 }
1717
1718 }
1719 }
1720
1721 #include <boost/math/special_functions/detail/ibeta_inverse.hpp>
1722 #include <boost/math/special_functions/detail/ibeta_inv_ab.hpp>
1723
1724 #endif