negative_binomial.hpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. // boost\math\special_functions\negative_binomial.hpp
  2. // Copyright Paul A. Bristow 2007.
  3. // Copyright John Maddock 2007.
  4. // Use, modification and distribution are subject to the
  5. // Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt
  7. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. // http://en.wikipedia.org/wiki/negative_binomial_distribution
  9. // http://mathworld.wolfram.com/NegativeBinomialDistribution.html
  10. // http://documents.wolfram.com/teachersedition/Teacher/Statistics/DiscreteDistributions.html
  11. // The negative binomial distribution NegativeBinomialDistribution[n, p]
  12. // is the distribution of the number (k) of failures that occur in a sequence of trials before
  13. // r successes have occurred, where the probability of success in each trial is p.
  14. // In a sequence of Bernoulli trials or events
  15. // (independent, yes or no, succeed or fail) with success_fraction probability p,
  16. // negative_binomial is the probability that k or fewer failures
  17. // precede the r th trial's success.
  18. // random variable k is the number of failures (NOT the probability).
  19. // Negative_binomial distribution is a discrete probability distribution.
  20. // But note that the negative binomial distribution
  21. // (like others including the binomial, Poisson & Bernoulli)
  22. // is strictly defined as a discrete function: only integral values of k are envisaged.
  23. // However because of the method of calculation using a continuous gamma function,
  24. // it is convenient to treat it as if a continuous function,
  25. // and permit non-integral values of k.
  26. // However, by default the policy is to use discrete_quantile_policy.
  27. // To enforce the strict mathematical model, users should use conversion
  28. // on k outside this function to ensure that k is integral.
  29. // MATHCAD cumulative negative binomial pnbinom(k, n, p)
  30. // Implementation note: much greater speed, and perhaps greater accuracy,
  31. // might be achieved for extreme values by using a normal approximation.
  32. // This is NOT been tested or implemented.
  33. #ifndef BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
  34. #define BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
  35. #include <boost/math/tools/config.hpp>
  36. #include <boost/math/tools/tuple.hpp>
  37. #include <boost/math/tools/numeric_limits.hpp>
  38. #include <boost/math/tools/cstdint.hpp>
  39. #include <boost/math/distributions/fwd.hpp>
  40. #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x) == Ix(a, b).
  41. #include <boost/math/distributions/complement.hpp> // complement.
  42. #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks domain_error & logic_error.
  43. #include <boost/math/special_functions/fpclassify.hpp> // isnan.
  44. #include <boost/math/tools/roots.hpp> // for root finding.
  45. #include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
  46. #include <boost/math/policies/error_handling.hpp>
  47. #if defined (BOOST_MSVC)
  48. # pragma warning(push)
  49. // This believed not now necessary, so commented out.
  50. //# pragma warning(disable: 4702) // unreachable code.
  51. // in domain_error_imp in error_handling.
  52. #endif
  53. namespace boost
  54. {
  55. namespace math
  56. {
  57. namespace negative_binomial_detail
  58. {
  59. // Common error checking routines for negative binomial distribution functions:
  60. template <class RealType, class Policy>
  61. BOOST_MATH_GPU_ENABLED inline bool check_successes(const char* function, const RealType& r, RealType* result, const Policy& pol)
  62. {
  63. if( !(boost::math::isfinite)(r) || (r <= 0) )
  64. {
  65. *result = policies::raise_domain_error<RealType>(
  66. function,
  67. "Number of successes argument is %1%, but must be > 0 !", r, pol);
  68. return false;
  69. }
  70. return true;
  71. }
  72. template <class RealType, class Policy>
  73. BOOST_MATH_GPU_ENABLED inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
  74. {
  75. if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) )
  76. {
  77. *result = policies::raise_domain_error<RealType>(
  78. function,
  79. "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
  80. return false;
  81. }
  82. return true;
  83. }
  84. template <class RealType, class Policy>
  85. BOOST_MATH_GPU_ENABLED inline bool check_dist(const char* function, const RealType& r, const RealType& p, RealType* result, const Policy& pol)
  86. {
  87. return check_success_fraction(function, p, result, pol)
  88. && check_successes(function, r, result, pol);
  89. }
  90. template <class RealType, class Policy>
  91. 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)
  92. {
  93. if(check_dist(function, r, p, result, pol) == false)
  94. {
  95. return false;
  96. }
  97. if( !(boost::math::isfinite)(k) || (k < 0) )
  98. { // Check k failures.
  99. *result = policies::raise_domain_error<RealType>(
  100. function,
  101. "Number of failures argument is %1%, but must be >= 0 !", k, pol);
  102. return false;
  103. }
  104. return true;
  105. } // Check_dist_and_k
  106. template <class RealType, class Policy>
  107. 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)
  108. {
  109. if((check_dist(function, r, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false)
  110. {
  111. return false;
  112. }
  113. return true;
  114. } // check_dist_and_prob
  115. } // namespace negative_binomial_detail
  116. template <class RealType = double, class Policy = policies::policy<> >
  117. class negative_binomial_distribution
  118. {
  119. public:
  120. typedef RealType value_type;
  121. typedef Policy policy_type;
  122. BOOST_MATH_GPU_ENABLED negative_binomial_distribution(RealType r, RealType p) : m_r(r), m_p(p)
  123. { // Constructor.
  124. RealType result;
  125. negative_binomial_detail::check_dist(
  126. "negative_binomial_distribution<%1%>::negative_binomial_distribution",
  127. m_r, // Check successes r > 0.
  128. m_p, // Check success_fraction 0 <= p <= 1.
  129. &result, Policy());
  130. } // negative_binomial_distribution constructor.
  131. // Private data getter class member functions.
  132. BOOST_MATH_GPU_ENABLED RealType success_fraction() const
  133. { // Probability of success as fraction in range 0 to 1.
  134. return m_p;
  135. }
  136. BOOST_MATH_GPU_ENABLED RealType successes() const
  137. { // Total number of successes r.
  138. return m_r;
  139. }
  140. BOOST_MATH_GPU_ENABLED static RealType find_lower_bound_on_p(
  141. RealType trials,
  142. RealType successes,
  143. RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
  144. {
  145. constexpr auto function = "boost::math::negative_binomial<%1%>::find_lower_bound_on_p";
  146. RealType result = 0; // of error checks.
  147. RealType failures = trials - successes;
  148. if(false == detail::check_probability(function, alpha, &result, Policy())
  149. && negative_binomial_detail::check_dist_and_k(
  150. function, successes, RealType(0), failures, &result, Policy()))
  151. {
  152. return result;
  153. }
  154. // Use complement ibeta_inv function for lower bound.
  155. // This is adapted from the corresponding binomial formula
  156. // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
  157. // This is a Clopper-Pearson interval, and may be overly conservative,
  158. // see also "A Simple Improved Inferential Method for Some
  159. // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
  160. // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
  161. //
  162. return ibeta_inv(successes, failures + 1, alpha, static_cast<RealType*>(nullptr), Policy());
  163. } // find_lower_bound_on_p
  164. BOOST_MATH_GPU_ENABLED static RealType find_upper_bound_on_p(
  165. RealType trials,
  166. RealType successes,
  167. RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
  168. {
  169. constexpr auto function = "boost::math::negative_binomial<%1%>::find_upper_bound_on_p";
  170. RealType result = 0; // of error checks.
  171. RealType failures = trials - successes;
  172. if(false == negative_binomial_detail::check_dist_and_k(
  173. function, successes, RealType(0), failures, &result, Policy())
  174. && detail::check_probability(function, alpha, &result, Policy()))
  175. {
  176. return result;
  177. }
  178. if(failures == 0)
  179. return 1;
  180. // Use complement ibetac_inv function for upper bound.
  181. // Note adjusted failures value: *not* failures+1 as usual.
  182. // This is adapted from the corresponding binomial formula
  183. // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
  184. // This is a Clopper-Pearson interval, and may be overly conservative,
  185. // see also "A Simple Improved Inferential Method for Some
  186. // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
  187. // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
  188. //
  189. return ibetac_inv(successes, failures, alpha, static_cast<RealType*>(nullptr), Policy());
  190. } // find_upper_bound_on_p
  191. // Estimate number of trials :
  192. // "How many trials do I need to be P% sure of seeing k or fewer failures?"
  193. BOOST_MATH_GPU_ENABLED static RealType find_minimum_number_of_trials(
  194. RealType k, // number of failures (k >= 0).
  195. RealType p, // success fraction 0 <= p <= 1.
  196. RealType alpha) // risk level threshold 0 <= alpha <= 1.
  197. {
  198. constexpr auto function = "boost::math::negative_binomial<%1%>::find_minimum_number_of_trials";
  199. // Error checks:
  200. RealType result = 0;
  201. if(false == negative_binomial_detail::check_dist_and_k(
  202. function, RealType(1), p, k, &result, Policy())
  203. && detail::check_probability(function, alpha, &result, Policy()))
  204. { return result; }
  205. result = ibeta_inva(k + 1, p, alpha, Policy()); // returns n - k
  206. return result + k;
  207. } // RealType find_number_of_failures
  208. BOOST_MATH_GPU_ENABLED static RealType find_maximum_number_of_trials(
  209. RealType k, // number of failures (k >= 0).
  210. RealType p, // success fraction 0 <= p <= 1.
  211. RealType alpha) // risk level threshold 0 <= alpha <= 1.
  212. {
  213. constexpr auto function = "boost::math::negative_binomial<%1%>::find_maximum_number_of_trials";
  214. // Error checks:
  215. RealType result = 0;
  216. if(false == negative_binomial_detail::check_dist_and_k(
  217. function, RealType(1), p, k, &result, Policy())
  218. && detail::check_probability(function, alpha, &result, Policy()))
  219. { return result; }
  220. result = ibetac_inva(k + 1, p, alpha, Policy()); // returns n - k
  221. return result + k;
  222. } // RealType find_number_of_trials complemented
  223. private:
  224. RealType m_r; // successes.
  225. RealType m_p; // success_fraction
  226. }; // template <class RealType, class Policy> class negative_binomial_distribution
  227. typedef negative_binomial_distribution<double> negative_binomial; // Reserved name of type double.
  228. #ifdef __cpp_deduction_guides
  229. template <class RealType>
  230. negative_binomial_distribution(RealType,RealType)->negative_binomial_distribution<typename boost::math::tools::promote_args<RealType>::type>;
  231. #endif
  232. template <class RealType, class Policy>
  233. BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> range(const negative_binomial_distribution<RealType, Policy>& /* dist */)
  234. { // Range of permissible values for random variable k.
  235. using boost::math::tools::max_value;
  236. return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // max_integer?
  237. }
  238. template <class RealType, class Policy>
  239. BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> support(const negative_binomial_distribution<RealType, Policy>& /* dist */)
  240. { // Range of supported values for random variable k.
  241. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
  242. using boost::math::tools::max_value;
  243. return boost::math::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // max_integer?
  244. }
  245. template <class RealType, class Policy>
  246. BOOST_MATH_GPU_ENABLED inline RealType mean(const negative_binomial_distribution<RealType, Policy>& dist)
  247. { // Mean of Negative Binomial distribution = r(1-p)/p.
  248. return dist.successes() * (1 - dist.success_fraction() ) / dist.success_fraction();
  249. } // mean
  250. //template <class RealType, class Policy>
  251. //inline RealType median(const negative_binomial_distribution<RealType, Policy>& dist)
  252. //{ // Median of negative_binomial_distribution is not defined.
  253. // return policies::raise_domain_error<RealType>(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
  254. //} // median
  255. // Now implemented via quantile(half) in derived accessors.
  256. template <class RealType, class Policy>
  257. BOOST_MATH_GPU_ENABLED inline RealType mode(const negative_binomial_distribution<RealType, Policy>& dist)
  258. { // Mode of Negative Binomial distribution = floor[(r-1) * (1 - p)/p]
  259. BOOST_MATH_STD_USING // ADL of std functions.
  260. return floor((dist.successes() -1) * (1 - dist.success_fraction()) / dist.success_fraction());
  261. } // mode
  262. template <class RealType, class Policy>
  263. BOOST_MATH_GPU_ENABLED inline RealType skewness(const negative_binomial_distribution<RealType, Policy>& dist)
  264. { // skewness of Negative Binomial distribution = 2-p / (sqrt(r(1-p))
  265. BOOST_MATH_STD_USING // ADL of std functions.
  266. RealType p = dist.success_fraction();
  267. RealType r = dist.successes();
  268. return (2 - p) /
  269. sqrt(r * (1 - p));
  270. } // skewness
  271. template <class RealType, class Policy>
  272. BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const negative_binomial_distribution<RealType, Policy>& dist)
  273. { // kurtosis of Negative Binomial distribution
  274. // http://en.wikipedia.org/wiki/Negative_binomial is kurtosis_excess so add 3
  275. RealType p = dist.success_fraction();
  276. RealType r = dist.successes();
  277. return 3 + (6 / r) + ((p * p) / (r * (1 - p)));
  278. } // kurtosis
  279. template <class RealType, class Policy>
  280. BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const negative_binomial_distribution<RealType, Policy>& dist)
  281. { // kurtosis excess of Negative Binomial distribution
  282. // http://mathworld.wolfram.com/Kurtosis.html table of kurtosis_excess
  283. RealType p = dist.success_fraction();
  284. RealType r = dist.successes();
  285. return (6 - p * (6-p)) / (r * (1-p));
  286. } // kurtosis_excess
  287. template <class RealType, class Policy>
  288. BOOST_MATH_GPU_ENABLED inline RealType variance(const negative_binomial_distribution<RealType, Policy>& dist)
  289. { // Variance of Binomial distribution = r (1-p) / p^2.
  290. return dist.successes() * (1 - dist.success_fraction())
  291. / (dist.success_fraction() * dist.success_fraction());
  292. } // variance
  293. // RealType standard_deviation(const negative_binomial_distribution<RealType, Policy>& dist)
  294. // standard_deviation provided by derived accessors.
  295. // RealType hazard(const negative_binomial_distribution<RealType, Policy>& dist)
  296. // hazard of Negative Binomial distribution provided by derived accessors.
  297. // RealType chf(const negative_binomial_distribution<RealType, Policy>& dist)
  298. // chf of Negative Binomial distribution provided by derived accessors.
  299. template <class RealType, class Policy>
  300. BOOST_MATH_GPU_ENABLED inline RealType pdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
  301. { // Probability Density/Mass Function.
  302. BOOST_FPU_EXCEPTION_GUARD
  303. constexpr auto function = "boost::math::pdf(const negative_binomial_distribution<%1%>&, %1%)";
  304. RealType r = dist.successes();
  305. RealType p = dist.success_fraction();
  306. RealType result = 0;
  307. if(false == negative_binomial_detail::check_dist_and_k(
  308. function,
  309. r,
  310. dist.success_fraction(),
  311. k,
  312. &result, Policy()))
  313. {
  314. return result;
  315. }
  316. result = (p/(r + k)) * ibeta_derivative(r, static_cast<RealType>(k+1), p, Policy());
  317. // Equivalent to:
  318. // return exp(lgamma(r + k) - lgamma(r) - lgamma(k+1)) * pow(p, r) * pow((1-p), k);
  319. return result;
  320. } // negative_binomial_pdf
  321. template <class RealType, class Policy>
  322. BOOST_MATH_GPU_ENABLED inline RealType cdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
  323. { // Cumulative Distribution Function of Negative Binomial.
  324. constexpr auto function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
  325. using boost::math::ibeta; // Regularized incomplete beta function.
  326. // k argument may be integral, signed, or unsigned, or floating point.
  327. // If necessary, it has already been promoted from an integral type.
  328. RealType p = dist.success_fraction();
  329. RealType r = dist.successes();
  330. // Error check:
  331. RealType result = 0;
  332. if(false == negative_binomial_detail::check_dist_and_k(
  333. function,
  334. r,
  335. dist.success_fraction(),
  336. k,
  337. &result, Policy()))
  338. {
  339. return result;
  340. }
  341. RealType probability = ibeta(r, static_cast<RealType>(k+1), p, Policy());
  342. // Ip(r, k+1) = ibeta(r, k+1, p)
  343. return probability;
  344. } // cdf Cumulative Distribution Function Negative Binomial.
  345. template <class RealType, class Policy>
  346. BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
  347. { // Complemented Cumulative Distribution Function Negative Binomial.
  348. constexpr auto function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
  349. using boost::math::ibetac; // Regularized incomplete beta function complement.
  350. // k argument may be integral, signed, or unsigned, or floating point.
  351. // If necessary, it has already been promoted from an integral type.
  352. RealType const& k = c.param;
  353. negative_binomial_distribution<RealType, Policy> const& dist = c.dist;
  354. RealType p = dist.success_fraction();
  355. RealType r = dist.successes();
  356. // Error check:
  357. RealType result = 0;
  358. if(false == negative_binomial_detail::check_dist_and_k(
  359. function,
  360. r,
  361. p,
  362. k,
  363. &result, Policy()))
  364. {
  365. return result;
  366. }
  367. // Calculate cdf negative binomial using the incomplete beta function.
  368. // Use of ibeta here prevents cancellation errors in calculating
  369. // 1-p if p is very small, perhaps smaller than machine epsilon.
  370. // Ip(k+1, r) = ibetac(r, k+1, p)
  371. // constrain_probability here?
  372. RealType probability = ibetac(r, static_cast<RealType>(k+1), p, Policy());
  373. // Numerical errors might cause probability to be slightly outside the range < 0 or > 1.
  374. // This might cause trouble downstream, so warn, possibly throw exception, but constrain to the limits.
  375. return probability;
  376. } // cdf Cumulative Distribution Function Negative Binomial.
  377. template <class RealType, class Policy>
  378. BOOST_MATH_GPU_ENABLED inline RealType quantile(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& P)
  379. { // Quantile, percentile/100 or Percent Point Negative Binomial function.
  380. // Return the number of expected failures k for a given probability p.
  381. // Inverse cumulative Distribution Function or Quantile (percentile / 100) of negative_binomial Probability.
  382. // MAthCAD pnbinom return smallest k such that negative_binomial(k, n, p) >= probability.
  383. // k argument may be integral, signed, or unsigned, or floating point.
  384. // BUT Cephes/CodeCogs says: finds argument p (0 to 1) such that cdf(k, n, p) = y
  385. constexpr auto function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
  386. BOOST_MATH_STD_USING // ADL of std functions.
  387. RealType p = dist.success_fraction();
  388. RealType r = dist.successes();
  389. // Check dist and P.
  390. RealType result = 0;
  391. if(false == negative_binomial_detail::check_dist_and_prob
  392. (function, r, p, P, &result, Policy()))
  393. {
  394. return result;
  395. }
  396. // Special cases.
  397. if (P == 1)
  398. { // Would need +infinity failures for total confidence.
  399. result = policies::raise_overflow_error<RealType>(
  400. function,
  401. "Probability argument is 1, which implies infinite failures !", Policy());
  402. return result;
  403. // usually means return +std::numeric_limits<RealType>::infinity();
  404. // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
  405. }
  406. if (P == 0)
  407. { // No failures are expected if P = 0.
  408. return 0; // Total trials will be just dist.successes.
  409. }
  410. if (P <= pow(dist.success_fraction(), dist.successes()))
  411. { // p <= pdf(dist, 0) == cdf(dist, 0)
  412. return 0;
  413. }
  414. if(p == 0)
  415. { // Would need +infinity failures for total confidence.
  416. result = policies::raise_overflow_error<RealType>(
  417. function,
  418. "Success fraction is 0, which implies infinite failures !", Policy());
  419. return result;
  420. // usually means return +std::numeric_limits<RealType>::infinity();
  421. // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
  422. }
  423. /*
  424. // Calculate quantile of negative_binomial using the inverse incomplete beta function.
  425. using boost::math::ibeta_invb;
  426. return ibeta_invb(r, p, P, Policy()) - 1; //
  427. */
  428. RealType guess = 0;
  429. RealType factor = 5;
  430. if(r * r * r * P * p > 0.005)
  431. guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), P, RealType(1-P), Policy());
  432. if(guess < 10)
  433. {
  434. //
  435. // Cornish-Fisher Negative binomial approximation not accurate in this area:
  436. //
  437. guess = BOOST_MATH_GPU_SAFE_MIN(RealType(r * 2), RealType(10));
  438. }
  439. else
  440. factor = (1-P < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
  441. BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
  442. //
  443. // Max iterations permitted:
  444. //
  445. boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
  446. typedef typename Policy::discrete_quantile_type discrete_type;
  447. return detail::inverse_discrete_quantile(
  448. dist,
  449. P,
  450. false,
  451. guess,
  452. factor,
  453. RealType(1),
  454. discrete_type(),
  455. max_iter);
  456. } // RealType quantile(const negative_binomial_distribution dist, p)
  457. template <class RealType, class Policy>
  458. BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
  459. { // Quantile or Percent Point Binomial function.
  460. // Return the number of expected failures k for a given
  461. // complement of the probability Q = 1 - P.
  462. constexpr auto function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
  463. BOOST_MATH_STD_USING
  464. // Error checks:
  465. RealType Q = c.param;
  466. const negative_binomial_distribution<RealType, Policy>& dist = c.dist;
  467. RealType p = dist.success_fraction();
  468. RealType r = dist.successes();
  469. RealType result = 0;
  470. if(false == negative_binomial_detail::check_dist_and_prob(
  471. function,
  472. r,
  473. p,
  474. Q,
  475. &result, Policy()))
  476. {
  477. return result;
  478. }
  479. // Special cases:
  480. //
  481. if(Q == 1)
  482. { // There may actually be no answer to this question,
  483. // since the probability of zero failures may be non-zero,
  484. return 0; // but zero is the best we can do:
  485. }
  486. if(Q == 0)
  487. { // Probability 1 - Q == 1 so infinite failures to achieve certainty.
  488. // Would need +infinity failures for total confidence.
  489. result = policies::raise_overflow_error<RealType>(
  490. function,
  491. "Probability argument complement is 0, which implies infinite failures !", Policy());
  492. return result;
  493. // usually means return +std::numeric_limits<RealType>::infinity();
  494. // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
  495. }
  496. if (-Q <= boost::math::powm1(dist.success_fraction(), dist.successes(), Policy()))
  497. { // q <= cdf(complement(dist, 0)) == pdf(dist, 0)
  498. return 0; //
  499. }
  500. if(p == 0)
  501. { // Success fraction is 0 so infinite failures to achieve certainty.
  502. // Would need +infinity failures for total confidence.
  503. result = policies::raise_overflow_error<RealType>(
  504. function,
  505. "Success fraction is 0, which implies infinite failures !", Policy());
  506. return result;
  507. // usually means return +std::numeric_limits<RealType>::infinity();
  508. // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
  509. }
  510. //return ibetac_invb(r, p, Q, Policy()) -1;
  511. RealType guess = 0;
  512. RealType factor = 5;
  513. if(r * r * r * (1-Q) * p > 0.005)
  514. guess = detail::inverse_negative_binomial_cornish_fisher(r, p, RealType(1-p), RealType(1-Q), Q, Policy());
  515. if(guess < 10)
  516. {
  517. //
  518. // Cornish-Fisher Negative binomial approximation not accurate in this area:
  519. //
  520. guess = BOOST_MATH_GPU_SAFE_MIN(RealType(r * 2), RealType(10));
  521. }
  522. else
  523. factor = (Q < sqrt(tools::epsilon<RealType>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
  524. BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
  525. //
  526. // Max iterations permitted:
  527. //
  528. boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
  529. typedef typename Policy::discrete_quantile_type discrete_type;
  530. return detail::inverse_discrete_quantile(
  531. dist,
  532. Q,
  533. true,
  534. guess,
  535. factor,
  536. RealType(1),
  537. discrete_type(),
  538. max_iter);
  539. } // quantile complement
  540. } // namespace math
  541. } // namespace boost
  542. // This include must be at the end, *after* the accessors
  543. // for this distribution have been defined, in order to
  544. // keep compilers that support two-phase lookup happy.
  545. #include <boost/math/distributions/detail/derived_accessors.hpp>
  546. #if defined (BOOST_MSVC)
  547. # pragma warning(pop)
  548. #endif
  549. #endif // BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP