Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:40:10

0001 //  (C) Copyright John Maddock 2006.
0002 //  Use, modification and distribution are subject to the
0003 //  Boost Software License, Version 1.0. (See accompanying file
0004 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // Implementation of Beta(a,b) using the Lanczos approximation:
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  // for ADL of std names
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    // Special cases:
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    // This code appears to be no longer necessary: it was
0067    // used to offset errors introduced from the Lanczos
0068    // approximation, but the current Lanczos approximations
0069    // are sufficiently accurate for all z that we can ditch
0070    // this.  It remains in the file for future reference...
0071    //
0072    // If a or b are less than 1, shift to greater than 1:
0073    if(a < 1)
0074    {
0075       prefix *= c / a;
0076       c += 1;
0077       a += 1;
0078    }
0079    if(b < 1)
0080    {
0081       prefix *= c / b;
0082       c += 1;
0083       b += 1;
0084    }
0085    */
0086 
0087    if(a < b)
0088       std::swap(a, b);
0089 
0090    // Lanczos calculation:
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       // Special case where the base of the power term is close to 1
0099       // compute (1+x)^y instead:
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       // this avoids possible overflow, but appears to be marginally less accurate:
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    // If a and b were originally less than 1 we need to scale the result:
0114    result *= prefix;
0115 
0116    return result;
0117 } // template <class T, class Lanczos> beta_imp(T a, T b, const Lanczos&)
0118 
0119 //
0120 // Generic implementation of Beta(a,b) without Lanczos approximation support
0121 // (Caution this is slow!!!):
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    // Special cases:
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    // Regular cases start here:
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       // Recursion:
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 } // template <class T>T beta_imp(T a, T b, const lanczos::undefined_lanczos& l)
0193 
0194 
0195 //
0196 // Compute the leading power terms in the incomplete Beta:
0197 //
0198 // (x^a)(y^b)/Beta(a,b) when normalised, and
0199 // (x^a)(y^b) otherwise.
0200 //
0201 // Almost all of the error in the incomplete beta comes from this
0202 // function: particularly when a and b are large. Computing large
0203 // powers are *hard* though, and using logarithms just leads to
0204 // horrendous cancellation errors.
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       // can we do better here?
0222       return pow(x, a) * pow(y, b);
0223    }
0224 
0225    T result;
0226 
0227    T c = a + b;
0228 
0229    // combine power terms with Lanczos approximation:
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;  // denominator overflows in this case
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    // combine with the leftover terms from the Lanczos approximation:
0239    result *= sqrt(bgh / boost::math::constants::e<T>());
0240    result *= sqrt(agh / cgh);
0241 
0242    // l1 and l2 are the base of the exponents minus one:
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       // when the base of the exponent is very near 1 we get really
0248       // gross errors unless extra care is taken:
0249       if((l1 * l2 > 0) || ((std::min)(a, b) < 1))
0250       {
0251          //
0252          // This first branch handles the simple cases where either:
0253          //
0254          // * The two power terms both go in the same direction
0255          // (towards zero or towards infinity).  In this case if either
0256          // term overflows or underflows, then the product of the two must
0257          // do so also.
0258          // *Alternatively if one exponent is less than one, then we
0259          // can't productively use it to eliminate overflow or underflow
0260          // from the other term.  Problems with spurious overflow/underflow
0261          // can't be ruled out in this case, but it is *very* unlikely
0262          // since one of the power terms will evaluate to a number close to 1.
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          // Both exponents are near one and both the exponents are
0289          // greater than one and further these two
0290          // power terms tend in opposite directions (one towards zero,
0291          // the other towards infinity), so we have to combine the terms
0292          // to avoid any risk of overflow or underflow.
0293          //
0294          // We do this by moving one power term inside the other, we have:
0295          //
0296          //    (1 + l1)^a * (1 + l2)^b
0297          //  = ((1 + l1)*(1 + l2)^(b/a))^a
0298          //  = (1 + l1 + l3 + l1*l3)^a   ;  l3 = (1 + l2)^(b/a) - 1
0299          //                                    = exp((b/a) * log(1 + l2)) - 1
0300          //
0301          // The tricky bit is deciding which term to move inside :-)
0302          // By preference we move the larger term inside, so that the
0303          // size of the largest exponent is reduced.  However, that can
0304          // only be done as long as l3 (see above) is also small.
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          // First base near 1 only:
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          // Second base near 1 only:
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       // general case:
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          // Oops, under/overflow, sidestep if we can:
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>(); // arbitrary large value if the logs would fail!
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             // This protects against spurious overflow in a/b:
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>();  // arbitrary large value if the logs would fail!
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)  // we can elude the calculation below if we're already going to be zero
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          // finally the normal case:
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;  // true zero
0427       if ((b > 1) && (y == 0))
0428          return result; // true zero
0429       return boost::math::policies::raise_underflow_error<T>(function, nullptr, pol);
0430    }
0431 
0432    return result;
0433 }
0434 //
0435 // Compute the leading power terms in the incomplete Beta:
0436 //
0437 // (x^a)(y^b)/Beta(a,b) when normalised, and
0438 // (x^a)(y^b) otherwise.
0439 //
0440 // Almost all of the error in the incomplete beta comes from this
0441 // function: particularly when a and b are large. Computing large
0442 // powers are *hard* though, and using logarithms just leads to
0443 // horrendous cancellation errors.
0444 //
0445 // This version is generic, slow, and does not use the Lanczos approximation.
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             // We calculate these logs purely so we can check for overflow in the power functions
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             // We calculate these logs purely so we can check for overflow in the power functions
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          // We want:
0536          //
0537          // (xc / a)^a (yc / b)^b
0538          //
0539          // But we know that one or other term will over / underflow and combining the logs will be next to useless as that will cause significant cancellation.
0540          // If we assume b > a and express z ^ b as(z ^ b / a) ^ a with z = (yc / b) then we can move one power term inside the other :
0541          //
0542          // ((xc / a) * (yc / b)^(b / a))^a
0543          //
0544          // However, we're not quite there yet, as the term being exponentiated is quite likely to be close to unity, so let:
0545          //
0546          // xc / a = 1 + (xb - ya) / a
0547          //
0548          // analogously let :
0549          //
0550          // 1 + p = (yc / b) ^ (b / a) = 1 + expm1((b / a) * log1p((ya - xb) / b))
0551          //
0552          // so putting the two together we have :
0553          //
0554          // exp(a * log1p((xb - ya) / a + p + p(xb - ya) / a))
0555          //
0556          // Analogously, when a > b we can just swap all the terms around.
0557          // 
0558          // Finally, there are a few cases (x or y is unity) when the above logic can't be used
0559          // or where there is no logarithmic cancellation and accuracy is better just using
0560          // the regular formula:
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             // The above logic fails, the result is almost certainly zero:
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 // Series approximation to the incomplete beta:
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       // incomplete beta power term, combined with the Lanczos approximation:
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;  // denorms cause overflow in the Lanzos series, result will be zero anyway
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       // Check for over/underflow in the power terms:
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          // Oh dear, we need logs, and this *will* cancel:
0698          //
0699          if (result != 0)  // elude calculation when result will be zero.
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       // Non-normalised, just compute the power:
0711       result = pow(x, a);
0712    }
0713    if(result < tools::min_value<T>())
0714       return s0; // Safeguard: series can't cope with denorms.
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 // Incomplete Beta series again, this time without Lanczos support:
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       // Non-normalised, just compute the power:
0772       result = pow(x, a);
0773    }
0774    if(result < tools::min_value<T>())
0775       return s0; // Safeguard: series can't cope with denorms.
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 // Continued fraction for the incomplete beta:
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 // Evaluate the incomplete beta via the continued fraction representation:
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 // Computes the difference between ibeta(a,b,x) and ibeta(a+k,b,x):
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    // series summation from 0 to k-1:
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 // This function is only needed for the non-regular incomplete beta,
0868 // it computes the delta in:
0869 // beta(a,b,x) = prefix + delta * beta(a+k,b,x)
0870 // it is currently only called for small k.
0871 //
0872 template <class T>
0873 inline T rising_factorial_ratio(T a, T b, int k)
0874 {
0875    // calculate:
0876    // (a)(a+1)(a+2)...(a+k-1)
0877    // _______________________
0878    // (b)(b+1)(b+2)...(b+k-1)
0879 
0880    // This is only called with small k, for large k
0881    // it is grossly inefficient, do not use outside it's
0882    // intended purpose!!!
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 // Routine for a > 15, b < 1
0893 //
0894 // Begin by figuring out how large our table of Pn's should be,
0895 // quoted accuracies are "guesstimates" based on empirical observation.
0896 // Note that the table size should never exceed the size of our
0897 // tables of factorials.
0898 //
0899 template <class T>
0900 struct Pn_size
0901 {
0902    // This is likely to be enough for ~35-50 digit accuracy
0903    // but it's hard to quantify exactly:
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; // ~8-15 digit accuracy
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; // 16-20 digit accuracy
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; // ~35-50 digit accuracy
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    // This is DiDonato and Morris's BGRAT routine, see Eq's 9 through 9.6.
0936    //
0937    // Some values we'll need later, these are Eq 9.1:
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    // and from from 9.2:
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    // now we need the quantity Pn, unfortunately this is computed
0964    // recursively, and requires a full history of all the previous values
0965    // so no choice but to declare a big table and hope it's big enough...
0966    //
0967    T p[ ::boost::math::detail::Pn_size<T>::value ] = { 1 };  // see 9.3.
0968    //
0969    // Now an initial value for J, see 9.6:
0970    //
0971    T j = boost::math::gamma_q(b, u, pol) / h;
0972    //
0973    // Now we can start to pull things together and evaluate the sum in Eq 9:
0974    //
0975    T sum = s0 + prefix * j;  // Value at N = 0
0976    // some variables we'll need:
0977    unsigned tnp1 = 1; // 2*N+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       // debugging code, enable this if you want to determine whether
0988       // the table of Pn's is large enough...
0989       //
0990       static int max_count = 2;
0991       if(n > max_count)
0992       {
0993          max_count = n;
0994          std::cerr << "Max iterations in BGRAT was " << n << std::endl;
0995       }
0996       */
0997       //
0998       // begin by evaluating the next Pn from Eq 9.4:
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       // Now we want Jn from Jn-1 using Eq 9.6:
1014       //
1015       j = (b2n * (b2n + 1) * j + (u + b2n + 1) * lxp) / t4;
1016       lxp *= lx2;
1017       b2n += 2;
1018       //
1019       // pull it together with Eq 9:
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 } // template <class T, class Lanczos>T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Lanczos& l, bool normalised)
1036 
1037 //
1038 // For integer arguments we can relate the incomplete beta to the
1039 // complement of the binomial distribution cdf and use this finite sum.
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 // ADL of std names
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       // First term underflows so we need to start at the mode of the
1060       // distribution and work outwards:
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          // OK, starting slightly above the mode didn't work,
1068          // we'll have to sum the terms the old fashioned way:
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 // The incomplete beta function implementation:
1098 // This is just a big bunch of spaghetti code to divide up the
1099 // input range and select the right implementation method for
1100 // each domain:
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 // for ADL of std math functions.
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; // value not set.
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       // extend to a few very special cases:
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       // We have an arcsine distribution:
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       // Special case see: http://functions.wolfram.com/GammaBetaErf/BetaRegularized/03/01/01/
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          // Both a,b < 1:
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                // Sidestep on a, and then use the series representation:
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          // One of a, b < 1 only:
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                // Sidestep to improve errors:
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       // Both a,b >= 1:
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             // relate to the binomial distribution and use a finite sum:
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             // sidestep so we can use the series representation:
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             // The formula here for the non-normalised case is tricky to figure
1449             // out (for me!!), and requires two pochhammer calculations rather
1450             // than one, so leave it for now and only use this in the normalized case....
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;  // Note this line would need changing if we ever enable this branch in non-normalized case
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             // overflow, return an arbitrarily large value:
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 } // template <class T, class Lanczos>T ibeta_imp(T a, T b, T x, const Lanczos& l, bool inv, bool normalised)
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    // start with the usual error checks:
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    // Now the corner cases:
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    // Now the regular cases:
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 // Some forwarding functions that disambiguate the third argument type:
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 } // namespace detail
1587 
1588 //
1589 // The actual function entry-points now follow, these just figure out
1590 // which Lanczos approximation to use
1591 // and forward to the implementation functions:
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 } // namespace math
1719 } // namespace boost
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 // BOOST_MATH_SPECIAL_BETA_HPP