Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/math/distributions/negative_binomial.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 // boost\math\special_functions\negative_binomial.hpp
0002 
0003 // Copyright Paul A. Bristow 2007.
0004 // Copyright John Maddock 2007.
0005 
0006 // Use, modification and distribution are subject to the
0007 // Boost Software License, Version 1.0.
0008 // (See accompanying file LICENSE_1_0.txt
0009 // or copy at http://www.boost.org/LICENSE_1_0.txt)
0010 
0011 // http://en.wikipedia.org/wiki/negative_binomial_distribution
0012 // http://mathworld.wolfram.com/NegativeBinomialDistribution.html
0013 // http://documents.wolfram.com/teachersedition/Teacher/Statistics/DiscreteDistributions.html
0014 
0015 // The negative binomial distribution NegativeBinomialDistribution[n, p]
0016 // is the distribution of the number (k) of failures that occur in a sequence of trials before
0017 // r successes have occurred, where the probability of success in each trial is p.
0018 
0019 // In a sequence of Bernoulli trials or events
0020 // (independent, yes or no, succeed or fail) with success_fraction probability p,
0021 // negative_binomial is the probability that k or fewer failures
0022 // precede the r th trial's success.
0023 // random variable k is the number of failures (NOT the probability).
0024 
0025 // Negative_binomial distribution is a discrete probability distribution.
0026 // But note that the negative binomial distribution
0027 // (like others including the binomial, Poisson & Bernoulli)
0028 // is strictly defined as a discrete function: only integral values of k are envisaged.
0029 // However because of the method of calculation using a continuous gamma function,
0030 // it is convenient to treat it as if a continuous function,
0031 // and permit non-integral values of k.
0032 
0033 // However, by default the policy is to use discrete_quantile_policy.
0034 
0035 // To enforce the strict mathematical model, users should use conversion
0036 // on k outside this function to ensure that k is integral.
0037 
0038 // MATHCAD cumulative negative binomial pnbinom(k, n, p)
0039 
0040 // Implementation note: much greater speed, and perhaps greater accuracy,
0041 // might be achieved for extreme values by using a normal approximation.
0042 // This is NOT been tested or implemented.
0043 
0044 #ifndef BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
0045 #define BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
0046 
0047 #include <boost/math/tools/config.hpp>
0048 #include <boost/math/tools/tuple.hpp>
0049 #include <boost/math/tools/numeric_limits.hpp>
0050 #include <boost/math/tools/cstdint.hpp>
0051 #include <boost/math/distributions/fwd.hpp>
0052 #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x) == Ix(a, b).
0053 #include <boost/math/distributions/complement.hpp> // complement.
0054 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks domain_error & logic_error.
0055 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0056 #include <boost/math/tools/roots.hpp> // for root finding.
0057 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
0058 #include <boost/math/policies/error_handling.hpp>
0059 
0060 #if defined (BOOST_MSVC)
0061 #  pragma warning(push)
0062 // This believed not now necessary, so commented out.
0063 //#  pragma warning(disable: 4702) // unreachable code.
0064 // in domain_error_imp in error_handling.
0065 #endif
0066 
0067 namespace boost
0068 {
0069   namespace math
0070   {
0071     namespace negative_binomial_detail
0072     {
0073       // Common error checking routines for negative binomial distribution functions:
0074       template <class RealType, class Policy>
0075       BOOST_MATH_GPU_ENABLED inline bool check_successes(const char* function, const RealType& r, RealType* result, const Policy& pol)
0076       {
0077         if( !(boost::math::isfinite)(r) || (r <= 0) )
0078         {
0079           *result = policies::raise_domain_error<RealType>(
0080             function,
0081             "Number of successes argument is %1%, but must be > 0 !", r, pol);
0082           return false;
0083         }
0084         return true;
0085       }
0086       template <class RealType, class Policy>
0087       BOOST_MATH_GPU_ENABLED inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
0088       {
0089         if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) )
0090         {
0091           *result = policies::raise_domain_error<RealType>(
0092             function,
0093             "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
0094           return false;
0095         }
0096         return true;
0097       }
0098       template <class RealType, class Policy>
0099       BOOST_MATH_GPU_ENABLED inline bool check_dist(const char* function, const RealType& r, const RealType& p, RealType* result, const Policy& pol)
0100       {
0101         return check_success_fraction(function, p, result, pol)
0102           && check_successes(function, r, result, pol);
0103       }
0104       template <class RealType, class Policy>
0105       BOOST_MATH_GPU_ENABLED inline bool check_dist_and_k(const char* function, const RealType& r, const RealType& p, RealType k, RealType* result, const Policy& pol)
0106       {
0107         if(check_dist(function, r, p, result, pol) == false)
0108         {
0109           return false;
0110         }
0111         if( !(boost::math::isfinite)(k) || (k < 0) )
0112         { // Check k failures.
0113           *result = policies::raise_domain_error<RealType>(
0114             function,
0115             "Number of failures argument is %1%, but must be >= 0 !", k, pol);
0116           return false;
0117         }
0118         return true;
0119       } // Check_dist_and_k
0120 
0121       template <class RealType, class Policy>
0122       BOOST_MATH_GPU_ENABLED inline bool check_dist_and_prob(const char* function, const RealType& r, RealType p, RealType prob, RealType* result, const Policy& pol)
0123       {
0124         if((check_dist(function, r, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false)
0125         {
0126           return false;
0127         }
0128         return true;
0129       } // check_dist_and_prob
0130     } //  namespace negative_binomial_detail
0131 
0132     template <class RealType = double, class Policy = policies::policy<> >
0133     class negative_binomial_distribution
0134     {
0135     public:
0136       typedef RealType value_type;
0137       typedef Policy policy_type;
0138 
0139       BOOST_MATH_GPU_ENABLED negative_binomial_distribution(RealType r, RealType p) : m_r(r), m_p(p)
0140       { // Constructor.
0141         RealType result;
0142         negative_binomial_detail::check_dist(
0143           "negative_binomial_distribution<%1%>::negative_binomial_distribution",
0144           m_r, // Check successes r > 0.
0145           m_p, // Check success_fraction 0 <= p <= 1.
0146           &result, Policy());
0147       } // negative_binomial_distribution constructor.
0148 
0149       // Private data getter class member functions.
0150       BOOST_MATH_GPU_ENABLED RealType success_fraction() const
0151       { // Probability of success as fraction in range 0 to 1.
0152         return m_p;
0153       }
0154       BOOST_MATH_GPU_ENABLED RealType successes() const
0155       { // Total number of successes r.
0156         return m_r;
0157       }
0158 
0159       BOOST_MATH_GPU_ENABLED static RealType find_lower_bound_on_p(
0160         RealType trials,
0161         RealType successes,
0162         RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
0163       {
0164         constexpr auto function = "boost::math::negative_binomial<%1%>::find_lower_bound_on_p";
0165         RealType result = 0;  // of error checks.
0166         RealType failures = trials - successes;
0167         if(false == detail::check_probability(function, alpha, &result, Policy())
0168           && negative_binomial_detail::check_dist_and_k(
0169           function, successes, RealType(0), failures, &result, Policy()))
0170         {
0171           return result;
0172         }
0173         // Use complement ibeta_inv function for lower bound.
0174         // This is adapted from the corresponding binomial formula
0175         // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
0176         // This is a Clopper-Pearson interval, and may be overly conservative,
0177         // see also "A Simple Improved Inferential Method for Some
0178         // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
0179         // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
0180         //
0181         return ibeta_inv(successes, failures + 1, alpha, static_cast<RealType*>(nullptr), Policy());
0182       } // find_lower_bound_on_p
0183 
0184       BOOST_MATH_GPU_ENABLED static RealType find_upper_bound_on_p(
0185         RealType trials,
0186         RealType successes,
0187         RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
0188       {
0189         constexpr auto function = "boost::math::negative_binomial<%1%>::find_upper_bound_on_p";
0190         RealType result = 0;  // of error checks.
0191         RealType failures = trials - successes;
0192         if(false == negative_binomial_detail::check_dist_and_k(
0193           function, successes, RealType(0), failures, &result, Policy())
0194           && detail::check_probability(function, alpha, &result, Policy()))
0195         {
0196           return result;
0197         }
0198         if(failures == 0)
0199            return 1;
0200         // Use complement ibetac_inv function for upper bound.
0201         // Note adjusted failures value: *not* failures+1 as usual.
0202         // This is adapted from the corresponding binomial formula
0203         // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
0204         // This is a Clopper-Pearson interval, and may be overly conservative,
0205         // see also "A Simple Improved Inferential Method for Some
0206         // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
0207         // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
0208         //
0209         return ibetac_inv(successes, failures, alpha, static_cast<RealType*>(nullptr), Policy());
0210       } // find_upper_bound_on_p
0211 
0212       // Estimate number of trials :
0213       // "How many trials do I need to be P% sure of seeing k or fewer failures?"
0214 
0215       BOOST_MATH_GPU_ENABLED static RealType find_minimum_number_of_trials(
0216         RealType k,     // number of failures (k >= 0).
0217         RealType p,     // success fraction 0 <= p <= 1.
0218         RealType alpha) // risk level threshold 0 <= alpha <= 1.
0219       {
0220         constexpr auto function = "boost::math::negative_binomial<%1%>::find_minimum_number_of_trials";
0221         // Error checks:
0222         RealType result = 0;
0223         if(false == negative_binomial_detail::check_dist_and_k(
0224           function, RealType(1), p, k, &result, Policy())
0225           && detail::check_probability(function, alpha, &result, Policy()))
0226         { return result; }
0227 
0228         result = ibeta_inva(k + 1, p, alpha, Policy());  // returns n - k
0229         return result + k;
0230       } // RealType find_number_of_failures
0231 
0232       BOOST_MATH_GPU_ENABLED static RealType find_maximum_number_of_trials(
0233         RealType k,     // number of failures (k >= 0).
0234         RealType p,     // success fraction 0 <= p <= 1.
0235         RealType alpha) // risk level threshold 0 <= alpha <= 1.
0236       {
0237         constexpr auto function = "boost::math::negative_binomial<%1%>::find_maximum_number_of_trials";
0238         // Error checks:
0239         RealType result = 0;
0240         if(false == negative_binomial_detail::check_dist_and_k(
0241           function, RealType(1), p, k, &result, Policy())
0242           &&  detail::check_probability(function, alpha, &result, Policy()))
0243         { return result; }
0244 
0245         result = ibetac_inva(k + 1, p, alpha, Policy());  // returns n - k
0246         return result + k;
0247       } // RealType find_number_of_trials complemented
0248 
0249     private:
0250       RealType m_r; // successes.
0251       RealType m_p; // success_fraction
0252     }; // template <class RealType, class Policy> class negative_binomial_distribution
0253 
0254     typedef negative_binomial_distribution<double> negative_binomial; // Reserved name of type double.
0255 
0256     #ifdef __cpp_deduction_guides
0257     template <class RealType>
0258     negative_binomial_distribution(RealType,RealType)->negative_binomial_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0259     #endif
0260 
0261     template <class RealType, class Policy>
0262     BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> range(const negative_binomial_distribution<RealType, Policy>& /* dist */)
0263     { // Range of permissible values for random variable k.
0264        using boost::math::tools::max_value;
0265        return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // max_integer?
0266     }
0267 
0268     template <class RealType, class Policy>
0269     BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> support(const negative_binomial_distribution<RealType, Policy>& /* dist */)
0270     { // Range of supported values for random variable k.
0271        // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
0272        using boost::math::tools::max_value;
0273        return boost::math::pair<RealType, RealType>(static_cast<RealType>(0),  max_value<RealType>()); // max_integer?
0274     }
0275 
0276     template <class RealType, class Policy>
0277     BOOST_MATH_GPU_ENABLED inline RealType mean(const negative_binomial_distribution<RealType, Policy>& dist)
0278     { // Mean of Negative Binomial distribution = r(1-p)/p.
0279       return dist.successes() * (1 - dist.success_fraction() ) / dist.success_fraction();
0280     } // mean
0281 
0282     //template <class RealType, class Policy>
0283     //inline RealType median(const negative_binomial_distribution<RealType, Policy>& dist)
0284     //{ // Median of negative_binomial_distribution is not defined.
0285     //  return policies::raise_domain_error<RealType>(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
0286     //} // median
0287     // Now implemented via quantile(half) in derived accessors.
0288 
0289     template <class RealType, class Policy>
0290     BOOST_MATH_GPU_ENABLED inline RealType mode(const negative_binomial_distribution<RealType, Policy>& dist)
0291     { // Mode of Negative Binomial distribution = floor[(r-1) * (1 - p)/p]
0292       BOOST_MATH_STD_USING // ADL of std functions.
0293       return floor((dist.successes() -1) * (1 - dist.success_fraction()) / dist.success_fraction());
0294     } // mode
0295 
0296     template <class RealType, class Policy>
0297     BOOST_MATH_GPU_ENABLED inline RealType skewness(const negative_binomial_distribution<RealType, Policy>& dist)
0298     { // skewness of Negative Binomial distribution = 2-p / (sqrt(r(1-p))
0299       BOOST_MATH_STD_USING // ADL of std functions.
0300       RealType p = dist.success_fraction();
0301       RealType r = dist.successes();
0302 
0303       return (2 - p) /
0304         sqrt(r * (1 - p));
0305     } // skewness
0306 
0307     template <class RealType, class Policy>
0308     BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const negative_binomial_distribution<RealType, Policy>& dist)
0309     { // kurtosis of Negative Binomial distribution
0310       // http://en.wikipedia.org/wiki/Negative_binomial is kurtosis_excess so add 3
0311       RealType p = dist.success_fraction();
0312       RealType r = dist.successes();
0313       return 3 + (6 / r) + ((p * p) / (r * (1 - p)));
0314     } // kurtosis
0315 
0316      template <class RealType, class Policy>
0317     BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const negative_binomial_distribution<RealType, Policy>& dist)
0318     { // kurtosis excess of Negative Binomial distribution
0319       // http://mathworld.wolfram.com/Kurtosis.html table of kurtosis_excess
0320       RealType p = dist.success_fraction();
0321       RealType r = dist.successes();
0322       return (6 - p * (6-p)) / (r * (1-p));
0323     } // kurtosis_excess
0324 
0325     template <class RealType, class Policy>
0326     BOOST_MATH_GPU_ENABLED inline RealType variance(const negative_binomial_distribution<RealType, Policy>& dist)
0327     { // Variance of Binomial distribution = r (1-p) / p^2.
0328       return  dist.successes() * (1 - dist.success_fraction())
0329         / (dist.success_fraction() * dist.success_fraction());
0330     } // variance
0331 
0332     // RealType standard_deviation(const negative_binomial_distribution<RealType, Policy>& dist)
0333     // standard_deviation provided by derived accessors.
0334     // RealType hazard(const negative_binomial_distribution<RealType, Policy>& dist)
0335     // hazard of Negative Binomial distribution provided by derived accessors.
0336     // RealType chf(const negative_binomial_distribution<RealType, Policy>& dist)
0337     // chf of Negative Binomial distribution provided by derived accessors.
0338 
0339     template <class RealType, class Policy>
0340     BOOST_MATH_GPU_ENABLED inline RealType pdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
0341     { // Probability Density/Mass Function.
0342       BOOST_FPU_EXCEPTION_GUARD
0343 
0344       constexpr auto function = "boost::math::pdf(const negative_binomial_distribution<%1%>&, %1%)";
0345 
0346       RealType r = dist.successes();
0347       RealType p = dist.success_fraction();
0348       RealType result = 0;
0349       if(false == negative_binomial_detail::check_dist_and_k(
0350         function,
0351         r,
0352         dist.success_fraction(),
0353         k,
0354         &result, Policy()))
0355       {
0356         return result;
0357       }
0358 
0359       result = (p/(r + k)) * ibeta_derivative(r, static_cast<RealType>(k+1), p, Policy());
0360       // Equivalent to:
0361       // return exp(lgamma(r + k) - lgamma(r) - lgamma(k+1)) * pow(p, r) * pow((1-p), k);
0362       return result;
0363     } // negative_binomial_pdf
0364 
0365     template <class RealType, class Policy>
0366     BOOST_MATH_GPU_ENABLED inline RealType cdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
0367     { // Cumulative Distribution Function of Negative Binomial.
0368       constexpr auto function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
0369       using boost::math::ibeta; // Regularized incomplete beta function.
0370       // k argument may be integral, signed, or unsigned, or floating point.
0371       // If necessary, it has already been promoted from an integral type.
0372       RealType p = dist.success_fraction();
0373       RealType r = dist.successes();
0374       // Error check:
0375       RealType result = 0;
0376       if(false == negative_binomial_detail::check_dist_and_k(
0377         function,
0378         r,
0379         dist.success_fraction(),
0380         k,
0381         &result, Policy()))
0382       {
0383         return result;
0384       }
0385 
0386       RealType probability = ibeta(r, static_cast<RealType>(k+1), p, Policy());
0387       // Ip(r, k+1) = ibeta(r, k+1, p)
0388       return probability;
0389     } // cdf Cumulative Distribution Function Negative Binomial.
0390 
0391       template <class RealType, class Policy>
0392       BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
0393       { // Complemented Cumulative Distribution Function Negative Binomial.
0394 
0395       constexpr auto function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
0396       using boost::math::ibetac; // Regularized incomplete beta function complement.
0397       // k argument may be integral, signed, or unsigned, or floating point.
0398       // If necessary, it has already been promoted from an integral type.
0399       RealType const& k = c.param;
0400       negative_binomial_distribution<RealType, Policy> const& dist = c.dist;
0401       RealType p = dist.success_fraction();
0402       RealType r = dist.successes();
0403       // Error check:
0404       RealType result = 0;
0405       if(false == negative_binomial_detail::check_dist_and_k(
0406         function,
0407         r,
0408         p,
0409         k,
0410         &result, Policy()))
0411       {
0412         return result;
0413       }
0414       // Calculate cdf negative binomial using the incomplete beta function.
0415       // Use of ibeta here prevents cancellation errors in calculating
0416       // 1-p if p is very small, perhaps smaller than machine epsilon.
0417       // Ip(k+1, r) = ibetac(r, k+1, p)
0418       // constrain_probability here?
0419      RealType probability = ibetac(r, static_cast<RealType>(k+1), p, Policy());
0420       // Numerical errors might cause probability to be slightly outside the range < 0 or > 1.
0421       // This might cause trouble downstream, so warn, possibly throw exception, but constrain to the limits.
0422       return probability;
0423     } // cdf Cumulative Distribution Function Negative Binomial.
0424 
0425     template <class RealType, class Policy>
0426     BOOST_MATH_GPU_ENABLED inline RealType quantile(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& P)
0427     { // Quantile, percentile/100 or Percent Point Negative Binomial function.
0428       // Return the number of expected failures k for a given probability p.
0429 
0430       // Inverse cumulative Distribution Function or Quantile (percentile / 100) of negative_binomial Probability.
0431       // MAthCAD pnbinom return smallest k such that negative_binomial(k, n, p) >= probability.
0432       // k argument may be integral, signed, or unsigned, or floating point.
0433       // BUT Cephes/CodeCogs says: finds argument p (0 to 1) such that cdf(k, n, p) = y
0434       constexpr auto function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
0435       BOOST_MATH_STD_USING // ADL of std functions.
0436 
0437       RealType p = dist.success_fraction();
0438       RealType r = dist.successes();
0439       // Check dist and P.
0440       RealType result = 0;
0441       if(false == negative_binomial_detail::check_dist_and_prob
0442         (function, r, p, P, &result, Policy()))
0443       {
0444         return result;
0445       }
0446 
0447       // Special cases.
0448       if (P == 1)
0449       {  // Would need +infinity failures for total confidence.
0450         result = policies::raise_overflow_error<RealType>(
0451             function,
0452             "Probability argument is 1, which implies infinite failures !", Policy());
0453         return result;
0454        // usually means return +std::numeric_limits<RealType>::infinity();
0455        // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
0456       }
0457       if (P == 0)
0458       { // No failures are expected if P = 0.
0459         return 0; // Total trials will be just dist.successes.
0460       }
0461       if (P <= pow(dist.success_fraction(), dist.successes()))
0462       { // p <= pdf(dist, 0) == cdf(dist, 0)
0463         return 0;
0464       }
0465       if(p == 0)
0466       {  // Would need +infinity failures for total confidence.
0467          result = policies::raise_overflow_error<RealType>(
0468             function,
0469             "Success fraction is 0, which implies infinite failures !", Policy());
0470          return result;
0471          // usually means return +std::numeric_limits<RealType>::infinity();
0472          // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
0473       }
0474       /*
0475       // Calculate quantile of negative_binomial using the inverse incomplete beta function.
0476       using boost::math::ibeta_invb;
0477       return ibeta_invb(r, p, P, Policy()) - 1; //
0478       */
0479       RealType guess = 0;
0480       RealType factor = 5;
0481       if(r * r * r * P * p > 0.005)
0482          guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), P, RealType(1-P), Policy());
0483 
0484       if(guess < 10)
0485       {
0486          //
0487          // Cornish-Fisher Negative binomial approximation not accurate in this area:
0488          //
0489          guess = BOOST_MATH_GPU_SAFE_MIN(RealType(r * 2), RealType(10));
0490       }
0491       else
0492          factor = (1-P < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
0493       BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
0494       //
0495       // Max iterations permitted:
0496       //
0497       boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0498       typedef typename Policy::discrete_quantile_type discrete_type;
0499       return detail::inverse_discrete_quantile(
0500          dist,
0501          P,
0502          false,
0503          guess,
0504          factor,
0505          RealType(1),
0506          discrete_type(),
0507          max_iter);
0508     } // RealType quantile(const negative_binomial_distribution dist, p)
0509 
0510     template <class RealType, class Policy>
0511     BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
0512     {  // Quantile or Percent Point Binomial function.
0513        // Return the number of expected failures k for a given
0514        // complement of the probability Q = 1 - P.
0515        constexpr auto function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
0516        BOOST_MATH_STD_USING
0517 
0518        // Error checks:
0519        RealType Q = c.param;
0520        const negative_binomial_distribution<RealType, Policy>& dist = c.dist;
0521        RealType p = dist.success_fraction();
0522        RealType r = dist.successes();
0523        RealType result = 0;
0524        if(false == negative_binomial_detail::check_dist_and_prob(
0525           function,
0526           r,
0527           p,
0528           Q,
0529           &result, Policy()))
0530        {
0531           return result;
0532        }
0533 
0534        // Special cases:
0535        //
0536        if(Q == 1)
0537        {  // There may actually be no answer to this question,
0538           // since the probability of zero failures may be non-zero,
0539           return 0; // but zero is the best we can do:
0540        }
0541        if(Q == 0)
0542        {  // Probability 1 - Q  == 1 so infinite failures to achieve certainty.
0543           // Would need +infinity failures for total confidence.
0544           result = policies::raise_overflow_error<RealType>(
0545              function,
0546              "Probability argument complement is 0, which implies infinite failures !", Policy());
0547           return result;
0548           // usually means return +std::numeric_limits<RealType>::infinity();
0549           // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
0550        }
0551        if (-Q <= boost::math::powm1(dist.success_fraction(), dist.successes(), Policy()))
0552        {  // q <= cdf(complement(dist, 0)) == pdf(dist, 0)
0553           return 0; //
0554        }
0555        if(p == 0)
0556        {  // Success fraction is 0 so infinite failures to achieve certainty.
0557           // Would need +infinity failures for total confidence.
0558           result = policies::raise_overflow_error<RealType>(
0559              function,
0560              "Success fraction is 0, which implies infinite failures !", Policy());
0561           return result;
0562           // usually means return +std::numeric_limits<RealType>::infinity();
0563           // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
0564        }
0565        //return ibetac_invb(r, p, Q, Policy()) -1;
0566        RealType guess = 0;
0567        RealType factor = 5;
0568        if(r * r * r * (1-Q) * p > 0.005)
0569           guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), RealType(1-Q), Q, Policy());
0570 
0571        if(guess < 10)
0572        {
0573           //
0574           // Cornish-Fisher Negative binomial approximation not accurate in this area:
0575           //
0576           guess = BOOST_MATH_GPU_SAFE_MIN(RealType(r * 2), RealType(10));
0577        }
0578        else
0579           factor = (Q < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
0580        BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
0581        //
0582        // Max iterations permitted:
0583        //
0584        boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0585        typedef typename Policy::discrete_quantile_type discrete_type;
0586        return detail::inverse_discrete_quantile(
0587           dist,
0588           Q,
0589           true,
0590           guess,
0591           factor,
0592           RealType(1),
0593           discrete_type(),
0594           max_iter);
0595     } // quantile complement
0596 
0597  } // namespace math
0598 } // namespace boost
0599 
0600 // This include must be at the end, *after* the accessors
0601 // for this distribution have been defined, in order to
0602 // keep compilers that support two-phase lookup happy.
0603 #include <boost/math/distributions/detail/derived_accessors.hpp>
0604 
0605 #if defined (BOOST_MSVC)
0606 # pragma warning(pop)
0607 #endif
0608 
0609 #endif // BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP