File indexing completed on 2025-09-18 08:49:03
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
0008 #define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
0009
0010 #ifdef _MSC_VER
0011 #pragma once
0012 #endif
0013
0014 #include <boost/math/tools/config.hpp>
0015 #include <boost/math/tools/precision.hpp>
0016 #include <boost/math/tools/roots.hpp>
0017 #include <boost/math/tools/tuple.hpp>
0018 #include <boost/math/special_functions/beta.hpp>
0019 #include <boost/math/special_functions/erf.hpp>
0020 #include <boost/math/special_functions/detail/t_distribution_inv.hpp>
0021 #include <boost/math/special_functions/fpclassify.hpp>
0022
0023 namespace boost{ namespace math{ namespace detail{
0024
0025
0026
0027
0028
0029 template <class T>
0030 struct temme_root_finder
0031 {
0032 BOOST_MATH_GPU_ENABLED temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {
0033 BOOST_MATH_ASSERT(
0034 math::tools::epsilon<T>() <= a && !(boost::math::isinf)(a));
0035 }
0036
0037 BOOST_MATH_GPU_ENABLED boost::math::tuple<T, T> operator()(T x)
0038 {
0039 BOOST_MATH_STD_USING
0040
0041 T y = 1 - x;
0042 T f = log(x) + a * log(y) + t;
0043 T f1 = (1 / x) - (a / (y));
0044 return boost::math::make_tuple(f, f1);
0045 }
0046 private:
0047 T t, a;
0048 };
0049
0050
0051
0052
0053
0054
0055
0056 template <class T, class Policy>
0057 BOOST_MATH_GPU_ENABLED T temme_method_1_ibeta_inverse(T a, T b, T z, const Policy& pol)
0058 {
0059 BOOST_MATH_STD_USING
0060
0061 const T r2 = sqrt(T(2));
0062
0063
0064
0065
0066 T eta0 = boost::math::erfc_inv(2 * z, pol);
0067 eta0 /= -sqrt(a / 2);
0068
0069 T terms[4] = { eta0 };
0070 T workspace[7];
0071
0072
0073
0074 T B = b - a;
0075 T B_2 = B * B;
0076 T B_3 = B_2 * B;
0077
0078
0079
0080
0081
0082 workspace[0] = -B * r2 / 2;
0083 workspace[1] = (1 - 2 * B) / 8;
0084 workspace[2] = -(B * r2 / 48);
0085 workspace[3] = T(-1) / 192;
0086 workspace[4] = -B * r2 / 3840;
0087 terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
0088
0089 workspace[0] = B * r2 * (3 * B - 2) / 12;
0090 workspace[1] = (20 * B_2 - 12 * B + 1) / 128;
0091 workspace[2] = B * r2 * (20 * B - 1) / 960;
0092 workspace[3] = (16 * B_2 + 30 * B - 15) / 4608;
0093 workspace[4] = B * r2 * (21 * B + 32) / 53760;
0094 workspace[5] = (-32 * B_2 + 63) / 368640;
0095 workspace[6] = -B * r2 * (120 * B + 17) / 25804480;
0096 terms[2] = tools::evaluate_polynomial(workspace, eta0, 7);
0097
0098 workspace[0] = B * r2 * (-75 * B_2 + 80 * B - 16) / 480;
0099 workspace[1] = (-1080 * B_3 + 868 * B_2 - 90 * B - 45) / 9216;
0100 workspace[2] = B * r2 * (-1190 * B_2 + 84 * B + 373) / 53760;
0101 workspace[3] = (-2240 * B_3 - 2508 * B_2 + 2100 * B - 165) / 368640;
0102 terms[3] = tools::evaluate_polynomial(workspace, eta0, 4);
0103
0104
0105
0106 T eta = tools::evaluate_polynomial(terms, T(1/a), 4);
0107
0108
0109
0110
0111 T eta_2 = eta * eta;
0112 T c = -exp(-eta_2 / 2);
0113 T x;
0114 if(eta_2 == 0)
0115 x = static_cast<T>(0.5f);
0116 else
0117 x = (1 + eta * sqrt((1 + c) / eta_2)) / 2;
0118
0119
0120
0121
0122
0123
0124 if (x < 0)
0125 x = 0;
0126 else if (x > 1)
0127 x = 1;
0128
0129 BOOST_MATH_ASSERT(eta * (x - 0.5) >= 0);
0130 #ifdef BOOST_INSTRUMENT
0131 std::cout << "Estimating x with Temme method 1: " << x << std::endl;
0132 #endif
0133 return x;
0134 }
0135
0136
0137
0138
0139
0140
0141
0142 template <class T, class Policy>
0143 BOOST_MATH_GPU_ENABLED T temme_method_2_ibeta_inverse(T , T , T z, T r, T theta, const Policy& pol)
0144 {
0145 BOOST_MATH_STD_USING
0146
0147
0148
0149
0150
0151 T eta0 = boost::math::erfc_inv(2 * z, pol);
0152 eta0 /= -sqrt(r / 2);
0153
0154 T s = sin(theta);
0155 T c = cos(theta);
0156
0157
0158
0159
0160
0161
0162
0163
0164 T terms[4] = { eta0 };
0165 T workspace[6];
0166
0167
0168
0169 T sc = s * c;
0170 T sc_2 = sc * sc;
0171 T sc_3 = sc_2 * sc;
0172 T sc_4 = sc_2 * sc_2;
0173 T sc_5 = sc_2 * sc_3;
0174 T sc_6 = sc_3 * sc_3;
0175 T sc_7 = sc_4 * sc_3;
0176
0177
0178
0179 workspace[0] = (2 * s * s - 1) / (3 * s * c);
0180 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co1[] = { -1, -5, 5 };
0181 workspace[1] = -tools::evaluate_even_polynomial(co1, s, 3) / (36 * sc_2);
0182 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co2[] = { 1, 21, -69, 46 };
0183 workspace[2] = tools::evaluate_even_polynomial(co2, s, 4) / (1620 * sc_3);
0184 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 7, -2, 33, -62, 31 };
0185 workspace[3] = -tools::evaluate_even_polynomial(co3, s, 5) / (6480 * sc_4);
0186 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 25, -52, -17, 88, -115, 46 };
0187 workspace[4] = tools::evaluate_even_polynomial(co4, s, 6) / (90720 * sc_5);
0188 terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
0189
0190
0191
0192 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co5[] = { 7, 12, -78, 52 };
0193 workspace[0] = -tools::evaluate_even_polynomial(co5, s, 4) / (405 * sc_3);
0194 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co6[] = { -7, 2, 183, -370, 185 };
0195 workspace[1] = tools::evaluate_even_polynomial(co6, s, 5) / (2592 * sc_4);
0196 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co7[] = { -533, 776, -1835, 10240, -13525, 5410 };
0197 workspace[2] = -tools::evaluate_even_polynomial(co7, s, 6) / (204120 * sc_5);
0198 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co8[] = { -1579, 3747, -3372, -15821, 45588, -45213, 15071 };
0199 workspace[3] = -tools::evaluate_even_polynomial(co8, s, 7) / (2099520 * sc_6);
0200 terms[2] = tools::evaluate_polynomial(workspace, eta0, 4);
0201
0202
0203
0204 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co9[] = {449, -1259, -769, 6686, -9260, 3704 };
0205 workspace[0] = tools::evaluate_even_polynomial(co9, s, 6) / (102060 * sc_5);
0206 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co10[] = { 63149, -151557, 140052, -727469, 2239932, -2251437, 750479 };
0207 workspace[1] = -tools::evaluate_even_polynomial(co10, s, 7) / (20995200 * sc_6);
0208 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co11[] = { 29233, -78755, 105222, 146879, -1602610, 3195183, -2554139, 729754 };
0209 workspace[2] = tools::evaluate_even_polynomial(co11, s, 8) / (36741600 * sc_7);
0210 terms[3] = tools::evaluate_polynomial(workspace, eta0, 3);
0211
0212
0213
0214
0215 T eta = tools::evaluate_polynomial(terms, T(1/r), 4);
0216
0217
0218
0219
0220
0221
0222
0223 T x;
0224 T s_2 = s * s;
0225 T c_2 = c * c;
0226 T alpha = c / s;
0227 alpha *= alpha;
0228 T lu = (-(eta * eta) / (2 * s_2) + log(s_2) + c_2 * log(c_2) / s_2);
0229
0230
0231
0232
0233 if(fabs(eta) < 0.7)
0234 {
0235
0236
0237
0238
0239 workspace[0] = s * s;
0240 workspace[1] = s * c;
0241 workspace[2] = (1 - 2 * workspace[0]) / 3;
0242 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co12[] = { 1, -13, 13 };
0243 workspace[3] = tools::evaluate_polynomial(co12, workspace[0], 3) / (36 * s * c);
0244 static const BOOST_MATH_INT_TABLE_TYPE(T, int) co13[] = { 1, 21, -69, 46 };
0245 workspace[4] = tools::evaluate_polynomial(co13, workspace[0], 4) / (270 * workspace[0] * c * c);
0246 x = tools::evaluate_polynomial(workspace, eta, 5);
0247 #ifdef BOOST_INSTRUMENT
0248 std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl;
0249 #endif
0250 }
0251 else
0252 {
0253
0254
0255
0256
0257
0258 T u = exp(lu);
0259 workspace[0] = u;
0260 workspace[1] = alpha;
0261 workspace[2] = 0;
0262 workspace[3] = 3 * alpha * (3 * alpha + 1) / 6;
0263 workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24;
0264 workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120;
0265 x = tools::evaluate_polynomial(workspace, u, 6);
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275 if((x - s_2) * eta < 0)
0276 x = 1 - x;
0277 #ifdef BOOST_INSTRUMENT
0278 std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl;
0279 #endif
0280 }
0281
0282
0283
0284
0285
0286
0287
0288 T lower, upper;
0289 if(eta < 0)
0290 {
0291 lower = 0;
0292 upper = s_2;
0293 }
0294 else
0295 {
0296 lower = s_2;
0297 upper = 1;
0298 }
0299
0300
0301
0302 if((x < lower) || (x > upper))
0303 x = (lower+upper) / 2;
0304
0305
0306
0307 #ifndef BOOST_MATH_NO_EXCEPTIONS
0308 try {
0309 #endif
0310 x = tools::newton_raphson_iterate(
0311 temme_root_finder<T>(-lu, alpha), x, lower, upper, policies::digits<T, Policy>() / 2);
0312 #ifndef BOOST_MATH_NO_EXCEPTIONS
0313 }
0314 catch (const boost::math::evaluation_error&)
0315 {
0316
0317
0318
0319
0320
0321
0322 }
0323 #endif
0324 return x;
0325 }
0326
0327
0328
0329
0330
0331
0332
0333 template <class T, class Policy>
0334 BOOST_MATH_GPU_ENABLED T temme_method_3_ibeta_inverse(T a, T b, T p, T q, const Policy& pol)
0335 {
0336 BOOST_MATH_STD_USING
0337
0338
0339
0340
0341
0342
0343 T eta0;
0344 if(p < q)
0345 eta0 = boost::math::gamma_q_inv(b, p, pol);
0346 else
0347 eta0 = boost::math::gamma_p_inv(b, q, pol);
0348 eta0 /= a;
0349
0350
0351
0352 T mu = b / a;
0353 T w = sqrt(1 + mu);
0354 T w_2 = w * w;
0355 T w_3 = w_2 * w;
0356 T w_4 = w_2 * w_2;
0357 T w_5 = w_3 * w_2;
0358 T w_6 = w_3 * w_3;
0359 T w_7 = w_4 * w_3;
0360 T w_8 = w_4 * w_4;
0361 T w_9 = w_5 * w_4;
0362 T w_10 = w_5 * w_5;
0363 T d = eta0 - mu;
0364 T d_2 = d * d;
0365 T d_3 = d_2 * d;
0366 T d_4 = d_2 * d_2;
0367 T w1 = w + 1;
0368 T w1_2 = w1 * w1;
0369 T w1_3 = w1 * w1_2;
0370 T w1_4 = w1_2 * w1_2;
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382 T e1 = (w + 2) * (w - 1) / (3 * w);
0383 e1 += (w_3 + 9 * w_2 + 21 * w + 5) * d / (36 * w_2 * w1);
0384 e1 -= (w_4 - 13 * w_3 + 69 * w_2 + 167 * w + 46) * d_2 / (1620 * w1_2 * w_3);
0385 e1 -= (7 * w_5 + 21 * w_4 + 70 * w_3 + 26 * w_2 - 93 * w - 31) * d_3 / (6480 * w1_3 * w_4);
0386 e1 -= (75 * w_6 + 202 * w_5 + 188 * w_4 - 888 * w_3 - 1345 * w_2 + 118 * w + 138) * d_4 / (272160 * w1_4 * w_5);
0387
0388 T e2 = (28 * w_4 + 131 * w_3 + 402 * w_2 + 581 * w + 208) * (w - 1) / (1620 * w1 * w_3);
0389 e2 -= (35 * w_6 - 154 * w_5 - 623 * w_4 - 1636 * w_3 - 3983 * w_2 - 3514 * w - 925) * d / (12960 * w1_2 * w_4);
0390 e2 -= (2132 * w_7 + 7915 * w_6 + 16821 * w_5 + 35066 * w_4 + 87490 * w_3 + 141183 * w_2 + 95993 * w + 21640) * d_2 / (816480 * w_5 * w1_3);
0391 e2 -= (11053 * w_8 + 53308 * w_7 + 117010 * w_6 + 163924 * w_5 + 116188 * w_4 - 258428 * w_3 - 677042 * w_2 - 481940 * w - 105497) * d_3 / (T(14696640) * w1_4 * w_6);
0392
0393 T e3 = -((3592 * w_7 + 8375 * w_6 - 1323 * w_5 - 29198 * w_4 - 89578 * w_3 - 154413 * w_2 - 116063 * w - 29632) * (w - 1)) / (816480 * w_5 * w1_2);
0394 e3 -= (442043 * w_9 + T(2054169) * w_8 + T(3803094) * w_7 + T(3470754) * w_6 + T(2141568) * w_5 - T(2393568) * w_4 - T(19904934) * w_3 - T(34714674) * w_2 - T(23128299) * w - T(5253353)) * d / (T(146966400) * w_6 * w1_3);
0395 e3 -= (116932 * w_10 + 819281 * w_9 + T(2378172) * w_8 + T(4341330) * w_7 + T(6806004) * w_6 + T(10622748) * w_5 + T(18739500) * w_4 + T(30651894) * w_3 + T(30869976) * w_2 + T(15431867) * w + T(2919016)) * d_2 / (T(146966400) * w1_4 * w_7);
0396
0397
0398
0399 T eta = eta0 + e1 / a + e2 / (a * a) + e3 / (a * a * a);
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418 if(eta <= 0)
0419 eta = tools::min_value<T>();
0420 T u = eta - mu * log(eta) + (1 + mu) * log(1 + mu) - mu;
0421 T cross = 1 / (1 + mu);
0422 T lower = eta < mu ? cross : 0;
0423 T upper = eta < mu ? 1 : cross;
0424 T x = (lower + upper) / 2;
0425
0426
0427 if (cross == 0 || cross == 1) { return cross; }
0428
0429 x = tools::newton_raphson_iterate(
0430 temme_root_finder<T>(u, mu), x, lower, upper, policies::digits<T, Policy>() / 2);
0431 #ifdef BOOST_INSTRUMENT
0432 std::cout << "Estimating x with Temme method 3: " << x << std::endl;
0433 #endif
0434 return x;
0435 }
0436
0437 template <class T, class Policy>
0438 struct ibeta_roots
0439 {
0440 BOOST_MATH_GPU_ENABLED ibeta_roots(T _a, T _b, T t, bool inv = false)
0441 : a(_a), b(_b), target(t), invert(inv) {}
0442
0443 BOOST_MATH_GPU_ENABLED boost::math::tuple<T, T, T> operator()(T x)
0444 {
0445 BOOST_MATH_STD_USING
0446
0447 BOOST_FPU_EXCEPTION_GUARD
0448
0449 T f1;
0450 T y = 1 - x;
0451 T f = ibeta_imp(a, b, x, Policy(), invert, true, &f1) - target;
0452 if(invert)
0453 f1 = -f1;
0454 if(y == 0)
0455 y = tools::min_value<T>() * 64;
0456 if(x == 0)
0457 x = tools::min_value<T>() * 64;
0458
0459 T f2 = f1 * (-y * a + (b - 2) * x + 1);
0460 if(fabs(f2) < y * x * tools::max_value<T>())
0461 f2 /= (y * x);
0462 if(invert)
0463 f2 = -f2;
0464
0465
0466 if(f1 == 0)
0467 f1 = (invert ? -1 : 1) * tools::min_value<T>() * 64;
0468
0469 return boost::math::make_tuple(f, f1, f2);
0470 }
0471 private:
0472 T a, b, target;
0473 bool invert;
0474 };
0475
0476 template <class T, class Policy>
0477 BOOST_MATH_GPU_ENABLED T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
0478 {
0479 BOOST_MATH_STD_USING
0480
0481
0482
0483
0484
0485 bool invert = false;
0486
0487
0488
0489 if(q == 0)
0490 {
0491 if(py) *py = 0;
0492 return 1;
0493 }
0494 else if(p == 0)
0495 {
0496 if(py) *py = 1;
0497 return 0;
0498 }
0499 else if(a == 1)
0500 {
0501 if(b == 1)
0502 {
0503 if(py) *py = 1 - p;
0504 return p;
0505 }
0506
0507 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0508 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0509 invert = true;
0510 }
0511
0512
0513
0514
0515 T x = 0;
0516
0517
0518 T y;
0519
0520
0521
0522
0523 T lower = 0;
0524 T upper = 1;
0525
0526
0527
0528
0529 if(a == 0.5f)
0530 {
0531 if(b == 0.5f)
0532 {
0533 x = sin(p * constants::half_pi<T>());
0534 x *= x;
0535 if(py)
0536 {
0537 *py = sin(q * constants::half_pi<T>());
0538 *py *= *py;
0539 }
0540 return x;
0541 }
0542 else if(b > 0.5f)
0543 {
0544 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0545 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0546 invert = !invert;
0547 }
0548 }
0549
0550
0551
0552 if((b == 0.5f) && (a >= 0.5f) && (p != 1))
0553 {
0554
0555
0556 x = find_ibeta_inv_from_t_dist(a, p, q, &y, pol);
0557 }
0558 else if(b == 1)
0559 {
0560 if(p < q)
0561 {
0562 if(a > 1)
0563 {
0564 x = pow(p, 1 / a);
0565 y = -boost::math::expm1(log(p) / a, pol);
0566 }
0567 else
0568 {
0569 x = pow(p, 1 / a);
0570 y = 1 - x;
0571 }
0572 }
0573 else
0574 {
0575 x = exp(boost::math::log1p(-q, pol) / a);
0576 y = -boost::math::expm1(boost::math::log1p(-q, pol) / a, pol);
0577 }
0578 if(invert)
0579 BOOST_MATH_GPU_SAFE_SWAP(x, y);
0580 if(py)
0581 *py = y;
0582 return x;
0583 }
0584 else if(a + b > 5)
0585 {
0586
0587
0588
0589
0590
0591
0592 if(p > 0.5)
0593 {
0594 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0595 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0596 invert = !invert;
0597 }
0598 T minv = BOOST_MATH_GPU_SAFE_MIN(a, b);
0599 T maxv = BOOST_MATH_GPU_SAFE_MAX(a, b);
0600 if((sqrt(minv) > (maxv - minv)) && (minv > 5))
0601 {
0602
0603
0604
0605
0606
0607
0608
0609
0610 x = temme_method_1_ibeta_inverse(a, b, p, pol);
0611 y = 1 - x;
0612 }
0613 else
0614 {
0615 T r = a + b;
0616 T theta = asin(sqrt(a / r));
0617 T lambda = minv / r;
0618 if((lambda >= 0.2) && (lambda <= 0.8) && (r >= 10))
0619 {
0620
0621
0622
0623
0624
0625
0626
0627
0628 T ppa = pow(p, 1/a);
0629 if((ppa < 0.0025) && (a + b < 200))
0630 {
0631 x = ppa * pow(a * boost::math::beta(a, b, pol), 1/a);
0632 }
0633 else
0634 x = temme_method_2_ibeta_inverse(a, b, p, r, theta, pol);
0635 y = 1 - x;
0636 }
0637 else
0638 {
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648 if(a < b)
0649 {
0650 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0651 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0652 invert = !invert;
0653 }
0654
0655
0656
0657 T bet = 0;
0658 if (b < 2)
0659 {
0660 #ifndef BOOST_MATH_NO_EXCEPTIONS
0661 try
0662 #endif
0663 {
0664 bet = boost::math::beta(a, b, pol);
0665
0666 typedef typename Policy::overflow_error_type overflow_type;
0667
0668 BOOST_MATH_IF_CONSTEXPR(overflow_type::value != boost::math::policies::throw_on_error)
0669 if(bet > tools::max_value<T>())
0670 bet = tools::max_value<T>();
0671 }
0672 #ifndef BOOST_MATH_NO_EXCEPTIONS
0673 catch (const std::overflow_error&)
0674 {
0675 bet = tools::max_value<T>();
0676 }
0677 #endif
0678 }
0679 if(bet != 0)
0680 {
0681 y = pow(b * q * bet, 1/b);
0682 x = 1 - y;
0683 }
0684 else
0685 y = 1;
0686 if(y > 1e-5)
0687 {
0688 x = temme_method_3_ibeta_inverse(a, b, p, q, pol);
0689 y = 1 - x;
0690 }
0691 }
0692 }
0693 }
0694 else if((a < 1) && (b < 1))
0695 {
0696
0697
0698
0699
0700 T xs = (1 - a) / (2 - a - b);
0701
0702
0703
0704
0705 T fs = boost::math::ibeta(a, b, xs, pol) - p;
0706 if(fabs(fs) / p < tools::epsilon<T>() * 3)
0707 {
0708
0709 *py = invert ? xs : 1 - xs;
0710 return invert ? 1-xs : xs;
0711 }
0712 if(fs < 0)
0713 {
0714 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0715 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0716 invert = !invert;
0717 xs = 1 - xs;
0718 }
0719 if ((a < tools::min_value<T>()) && (b > tools::min_value<T>()))
0720 {
0721 if (py)
0722 {
0723 *py = invert ? 0 : 1;
0724 }
0725 return invert ? 1 : 0;
0726 }
0727
0728
0729
0730
0731 T bet = 0;
0732 T xg;
0733 bool overflow = false;
0734 #ifndef BOOST_MATH_NO_EXCEPTIONS
0735 try {
0736 #endif
0737 bet = boost::math::beta(a, b, pol);
0738 #ifndef BOOST_MATH_NO_EXCEPTIONS
0739 }
0740 catch (const std::runtime_error&)
0741 {
0742 overflow = true;
0743 }
0744 #endif
0745 if (overflow || !(boost::math::isfinite)(bet))
0746 {
0747 xg = exp((boost::math::lgamma(a + 1, pol) + boost::math::lgamma(b, pol) - boost::math::lgamma(a + b, pol) + log(p)) / a);
0748 if (xg > 2 / tools::epsilon<T>())
0749 xg = 2 / tools::epsilon<T>();
0750 }
0751 else
0752 xg = pow(a * p * bet, 1/a);
0753 x = xg / (1 + xg);
0754 y = 1 / (1 + xg);
0755
0756
0757
0758
0759 if(x > xs)
0760 x = xs;
0761 upper = xs;
0762 }
0763 else if((a > 1) && (b > 1))
0764 {
0765
0766
0767
0768
0769
0770
0771
0772 T xs = (a - 1) / (a + b - 2);
0773 T xs2 = (b - 1) / (a + b - 2);
0774 T ps = boost::math::ibeta(a, b, xs, pol) - p;
0775
0776 if(ps < 0)
0777 {
0778 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0779 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0780 BOOST_MATH_GPU_SAFE_SWAP(xs, xs2);
0781 invert = !invert;
0782 }
0783
0784
0785
0786
0787 T lx = log(p * a * boost::math::beta(a, b, pol)) / a;
0788 x = exp(lx);
0789 y = x < 0.9 ? T(1 - x) : (T)(-boost::math::expm1(lx, pol));
0790
0791 if((b < a) && (x < 0.2))
0792 {
0793
0794
0795
0796
0797 T ap1 = a - 1;
0798 T bm1 = b - 1;
0799 T a_2 = a * a;
0800 T a_3 = a * a_2;
0801 T b_2 = b * b;
0802 T terms[5] = { 0, 1 };
0803 terms[2] = bm1 / ap1;
0804 ap1 *= ap1;
0805 terms[3] = bm1 * (3 * a * b + 5 * b + a_2 - a - 4) / (2 * (a + 2) * ap1);
0806 ap1 *= (a + 1);
0807 terms[4] = bm1 * (33 * a * b_2 + 31 * b_2 + 8 * a_2 * b_2 - 30 * a * b - 47 * b + 11 * a_2 * b + 6 * a_3 * b + 18 + 4 * a - a_3 + a_2 * a_2 - 10 * a_2)
0808 / (3 * (a + 3) * (a + 2) * ap1);
0809 x = tools::evaluate_polynomial(terms, x, 5);
0810 }
0811
0812
0813
0814
0815 if(x > xs)
0816 x = xs;
0817 upper = xs;
0818 }
0819 else
0820 {
0821
0822
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836
0837
0838
0839
0840
0841 if(b < a)
0842 {
0843 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0844 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0845 invert = !invert;
0846 }
0847 if (a < tools::min_value<T>())
0848 {
0849
0850 if (p < 1)
0851 {
0852 x = 1;
0853 y = 0;
0854 }
0855 else
0856 {
0857 x = 0;
0858 y = 1;
0859 }
0860 }
0861 else if(pow(p, 1/a) < 0.5)
0862 {
0863 #ifndef BOOST_MATH_NO_EXCEPTIONS
0864 try
0865 {
0866 #endif
0867 x = pow(p * a * boost::math::beta(a, b, pol), 1 / a);
0868 if ((x > 1) || !(boost::math::isfinite)(x))
0869 x = 1;
0870 #ifndef BOOST_MATH_NO_EXCEPTIONS
0871 }
0872 catch (const std::overflow_error&)
0873 {
0874 x = 1;
0875 }
0876 #endif
0877 if(x == 0)
0878 x = boost::math::tools::min_value<T>();
0879 y = 1 - x;
0880 }
0881 else
0882 {
0883
0884 #ifndef BOOST_MATH_NO_EXCEPTIONS
0885 try
0886 {
0887 #endif
0888 y = pow(1 - pow(p, b * boost::math::beta(a, b, pol)), 1/b);
0889 if ((y > 1) || !(boost::math::isfinite)(y))
0890 y = 1;
0891 #ifndef BOOST_MATH_NO_EXCEPTIONS
0892 }
0893 catch (const std::overflow_error&)
0894 {
0895 y = 1;
0896 }
0897 #endif
0898 if(y == 0)
0899 y = boost::math::tools::min_value<T>();
0900 x = 1 - y;
0901 }
0902 }
0903
0904
0905
0906
0907
0908 if(x > 0.5)
0909 {
0910 BOOST_MATH_GPU_SAFE_SWAP(a, b);
0911 BOOST_MATH_GPU_SAFE_SWAP(p, q);
0912 BOOST_MATH_GPU_SAFE_SWAP(x, y);
0913 invert = !invert;
0914 T l = 1 - upper;
0915 T u = 1 - lower;
0916 lower = l;
0917 upper = u;
0918 }
0919
0920
0921
0922
0923
0924
0925
0926 if(lower == 0)
0927 {
0928 if(invert && (py == 0))
0929 {
0930
0931
0932
0933 lower = boost::math::tools::epsilon<T>();
0934 if(x < lower)
0935 x = lower;
0936 }
0937 else
0938 lower = boost::math::tools::min_value<T>();
0939 if(x < lower)
0940 x = lower;
0941 }
0942 boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0943 boost::math::uintmax_t max_iter_used = 0;
0944
0945
0946
0947 int digits = boost::math::policies::digits<T, Policy>() / 2;
0948 if((x < 1e-50) && ((a < 1) || (b < 1)))
0949 {
0950
0951
0952
0953
0954
0955
0956
0957
0958
0959 digits *= 3;
0960 digits /= 2;
0961 }
0962
0963
0964
0965
0966
0967
0968 #ifndef BOOST_MATH_HAS_GPU_SUPPORT
0969 x = boost::math::tools::halley_iterate(
0970 #else
0971 x = boost::math::tools::newton_raphson_iterate(
0972 #endif
0973 boost::math::detail::ibeta_roots<T, Policy>(a, b, (p < q ? p : q), (p < q ? false : true)), x, lower, upper, digits, max_iter);
0974 policies::check_root_iterations<T>("boost::math::ibeta<%1%>(%1%, %1%, %1%)", max_iter + max_iter_used, pol);
0975
0976
0977
0978
0979
0980
0981
0982
0983
0984 if(x == lower)
0985 x = 0;
0986 if(py)
0987 *py = invert ? x : 1 - x;
0988 return invert ? 1-x : x;
0989 }
0990
0991 }
0992
0993 template <class T1, class T2, class T3, class T4, class Policy>
0994 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3, T4>::type
0995 ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol)
0996 {
0997 constexpr auto function = "boost::math::ibeta_inv<%1%>(%1%,%1%,%1%)";
0998 BOOST_FPU_EXCEPTION_GUARD
0999 typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
1000 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1001 typedef typename policies::normalise<
1002 Policy,
1003 policies::promote_float<false>,
1004 policies::promote_double<false>,
1005 policies::discrete_quantile<>,
1006 policies::assert_undefined<> >::type forwarding_policy;
1007
1008 if(a <= 0)
1009 return policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
1010 if(b <= 0)
1011 return policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
1012 if((p < 0) || (p > 1))
1013 return policies::raise_domain_error<result_type>(function, "Argument p outside the range [0,1] in the incomplete beta function inverse (got p=%1%).", p, pol);
1014
1015 value_type rx, ry;
1016
1017 rx = detail::ibeta_inv_imp(
1018 static_cast<value_type>(a),
1019 static_cast<value_type>(b),
1020 static_cast<value_type>(p),
1021 static_cast<value_type>(1 - p),
1022 forwarding_policy(), &ry);
1023
1024 if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
1025 return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
1026 }
1027
1028 template <class T1, class T2, class T3, class T4>
1029 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3, T4>::type
1030 ibeta_inv(T1 a, T2 b, T3 p, T4* py)
1031 {
1032 return ibeta_inv(a, b, p, py, policies::policy<>());
1033 }
1034
1035 template <class T1, class T2, class T3>
1036 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3>::type
1037 ibeta_inv(T1 a, T2 b, T3 p)
1038 {
1039 typedef typename tools::promote_args<T1, T2, T3>::type result_type;
1040 return ibeta_inv(a, b, p, static_cast<result_type*>(nullptr), policies::policy<>());
1041 }
1042
1043 template <class T1, class T2, class T3, class Policy>
1044 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3>::type
1045 ibeta_inv(T1 a, T2 b, T3 p, const Policy& pol)
1046 {
1047 typedef typename tools::promote_args<T1, T2, T3>::type result_type;
1048 return ibeta_inv(a, b, p, static_cast<result_type*>(nullptr), pol);
1049 }
1050
1051 template <class T1, class T2, class T3, class T4, class Policy>
1052 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3, T4>::type
1053 ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol)
1054 {
1055 constexpr auto function = "boost::math::ibetac_inv<%1%>(%1%,%1%,%1%)";
1056 BOOST_FPU_EXCEPTION_GUARD
1057 typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
1058 typedef typename policies::evaluation<result_type, Policy>::type value_type;
1059 typedef typename policies::normalise<
1060 Policy,
1061 policies::promote_float<false>,
1062 policies::promote_double<false>,
1063 policies::discrete_quantile<>,
1064 policies::assert_undefined<> >::type forwarding_policy;
1065
1066 if(a <= 0)
1067 return policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
1068 if(b <= 0)
1069 return policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
1070 if((q < 0) || (q > 1))
1071 return policies::raise_domain_error<result_type>(function, "Argument q outside the range [0,1] in the incomplete beta function inverse (got q=%1%).", q, pol);
1072
1073 value_type rx, ry;
1074
1075 rx = detail::ibeta_inv_imp(
1076 static_cast<value_type>(a),
1077 static_cast<value_type>(b),
1078 static_cast<value_type>(1 - q),
1079 static_cast<value_type>(q),
1080 forwarding_policy(), &ry);
1081
1082 if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
1083 return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
1084 }
1085
1086 template <class T1, class T2, class T3, class T4>
1087 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<T1, T2, T3, T4>::type
1088 ibetac_inv(T1 a, T2 b, T3 q, T4* py)
1089 {
1090 return ibetac_inv(a, b, q, py, policies::policy<>());
1091 }
1092
1093 template <class RT1, class RT2, class RT3>
1094 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1095 ibetac_inv(RT1 a, RT2 b, RT3 q)
1096 {
1097 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1098 return ibetac_inv(a, b, q, static_cast<result_type*>(nullptr), policies::policy<>());
1099 }
1100
1101 template <class RT1, class RT2, class RT3, class Policy>
1102 BOOST_MATH_GPU_ENABLED inline typename tools::promote_args<RT1, RT2, RT3>::type
1103 ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy& pol)
1104 {
1105 typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
1106 return ibetac_inv(a, b, q, static_cast<result_type*>(nullptr), pol);
1107 }
1108
1109 }
1110 }
1111
1112 #endif
1113
1114
1115
1116