File indexing completed on 2025-01-30 09:45:23
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 #ifndef BOOST_MATH_SPECIAL_BINOMIAL_HPP
0080 #define BOOST_MATH_SPECIAL_BINOMIAL_HPP
0081
0082 #include <boost/math/distributions/fwd.hpp>
0083 #include <boost/math/special_functions/beta.hpp> // for incomplete beta.
0084 #include <boost/math/distributions/complement.hpp> // complements
0085 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
0086 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp> // error checks
0087 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
0088 #include <boost/math/tools/roots.hpp> // for root finding.
0089
0090 #include <utility>
0091
0092 namespace boost
0093 {
0094 namespace math
0095 {
0096
0097 template <class RealType, class Policy>
0098 class binomial_distribution;
0099
0100 namespace binomial_detail{
0101
0102 template <class RealType, class Policy>
0103 inline bool check_N(const char* function, const RealType& N, RealType* result, const Policy& pol)
0104 {
0105 if((N < 0) || !(boost::math::isfinite)(N))
0106 {
0107 *result = policies::raise_domain_error<RealType>(
0108 function,
0109 "Number of Trials argument is %1%, but must be >= 0 !", N, pol);
0110 return false;
0111 }
0112 return true;
0113 }
0114 template <class RealType, class Policy>
0115 inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
0116 {
0117 if((p < 0) || (p > 1) || !(boost::math::isfinite)(p))
0118 {
0119 *result = policies::raise_domain_error<RealType>(
0120 function,
0121 "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
0122 return false;
0123 }
0124 return true;
0125 }
0126 template <class RealType, class Policy>
0127 inline bool check_dist(const char* function, const RealType& N, const RealType& p, RealType* result, const Policy& pol)
0128 {
0129 return check_success_fraction(
0130 function, p, result, pol)
0131 && check_N(
0132 function, N, result, pol);
0133 }
0134 template <class RealType, class Policy>
0135 inline bool check_dist_and_k(const char* function, const RealType& N, const RealType& p, RealType k, RealType* result, const Policy& pol)
0136 {
0137 if(check_dist(function, N, p, result, pol) == false)
0138 return false;
0139 if((k < 0) || !(boost::math::isfinite)(k))
0140 {
0141 *result = policies::raise_domain_error<RealType>(
0142 function,
0143 "Number of Successes argument is %1%, but must be >= 0 !", k, pol);
0144 return false;
0145 }
0146 if(k > N)
0147 {
0148 *result = policies::raise_domain_error<RealType>(
0149 function,
0150 "Number of Successes argument is %1%, but must be <= Number of Trials !", k, pol);
0151 return false;
0152 }
0153 return true;
0154 }
0155 template <class RealType, class Policy>
0156 inline bool check_dist_and_prob(const char* function, const RealType& N, RealType p, RealType prob, RealType* result, const Policy& pol)
0157 {
0158 if((check_dist(function, N, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false)
0159 return false;
0160 return true;
0161 }
0162
0163 template <class T, class Policy>
0164 T inverse_binomial_cornish_fisher(T n, T sf, T p, T q, const Policy& pol)
0165 {
0166 BOOST_MATH_STD_USING
0167
0168 T m = n * sf;
0169
0170 T sigma = sqrt(n * sf * (1 - sf));
0171
0172 T sk = (1 - 2 * sf) / sigma;
0173
0174
0175
0176 T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
0177
0178 if(p < 0.5)
0179 x = -x;
0180 T x2 = x * x;
0181
0182 T w = x + sk * (x2 - 1) / 6;
0183
0184
0185
0186
0187
0188
0189
0190 w = m + sigma * w;
0191 if(w < tools::min_value<T>())
0192 return sqrt(tools::min_value<T>());
0193 if(w > n)
0194 return n;
0195 return w;
0196 }
0197
0198 template <class RealType, class Policy>
0199 RealType quantile_imp(const binomial_distribution<RealType, Policy>& dist, const RealType& p, const RealType& q, bool comp)
0200 {
0201
0202
0203
0204
0205 BOOST_MATH_STD_USING
0206 RealType result = 0;
0207 RealType trials = dist.trials();
0208 RealType success_fraction = dist.success_fraction();
0209 if(false == binomial_detail::check_dist_and_prob(
0210 "boost::math::quantile(binomial_distribution<%1%> const&, %1%)",
0211 trials,
0212 success_fraction,
0213 p,
0214 &result, Policy()))
0215 {
0216 return result;
0217 }
0218
0219
0220
0221 if(p == 0)
0222 {
0223
0224
0225 return 0;
0226 }
0227 if(p == 1 || success_fraction == 1)
0228 {
0229
0230 return trials;
0231 }
0232 if (p <= pow(1 - success_fraction, trials))
0233 {
0234 return 0;
0235 }
0236
0237
0238
0239 RealType guess = binomial_detail::inverse_binomial_cornish_fisher(trials, success_fraction, p, q, Policy());
0240 RealType factor = 8;
0241 if(trials > 100)
0242 factor = 1.01f;
0243 else if((trials > 10) && (trials - 1 > guess) && (guess > 3))
0244 factor = 1.15f;
0245 else if(trials < 10)
0246 {
0247
0248 if(guess > trials / 64)
0249 {
0250 guess = trials / 4;
0251 factor = 2;
0252 }
0253 else
0254 guess = trials / 1024;
0255 }
0256 else
0257 factor = 2;
0258
0259 typedef typename Policy::discrete_quantile_type discrete_quantile_type;
0260 std::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0261 return detail::inverse_discrete_quantile(
0262 dist,
0263 comp ? q : p,
0264 comp,
0265 guess,
0266 factor,
0267 RealType(1),
0268 discrete_quantile_type(),
0269 max_iter);
0270 }
0271
0272 }
0273
0274 template <class RealType = double, class Policy = policies::policy<> >
0275 class binomial_distribution
0276 {
0277 public:
0278 typedef RealType value_type;
0279 typedef Policy policy_type;
0280
0281 binomial_distribution(RealType n = 1, RealType p = 0.5) : m_n(n), m_p(p)
0282 {
0283
0284 RealType r;
0285 binomial_detail::check_dist(
0286 "boost::math::binomial_distribution<%1%>::binomial_distribution",
0287 m_n,
0288 m_p,
0289 &r, Policy());
0290 }
0291
0292 RealType success_fraction() const
0293 {
0294 return m_p;
0295 }
0296 RealType trials() const
0297 {
0298 return m_n;
0299 }
0300
0301 enum interval_type{
0302 clopper_pearson_exact_interval,
0303 jeffreys_prior_interval
0304 };
0305
0306
0307
0308
0309
0310
0311
0312 static RealType find_lower_bound_on_p(
0313 RealType trials,
0314 RealType successes,
0315 RealType probability,
0316 interval_type t = clopper_pearson_exact_interval)
0317 {
0318 static const char* function = "boost::math::binomial_distribution<%1%>::find_lower_bound_on_p";
0319
0320 RealType result = 0;
0321 if(false == binomial_detail::check_dist_and_k(
0322 function, trials, RealType(0), successes, &result, Policy())
0323 &&
0324 binomial_detail::check_dist_and_prob(
0325 function, trials, RealType(0), probability, &result, Policy()))
0326 { return result; }
0327
0328 if(successes == 0)
0329 return 0;
0330
0331
0332
0333
0334 return (t == clopper_pearson_exact_interval) ? ibeta_inv(successes, trials - successes + 1, probability, static_cast<RealType*>(nullptr), Policy())
0335 : ibeta_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast<RealType*>(nullptr), Policy());
0336 }
0337 static RealType find_upper_bound_on_p(
0338 RealType trials,
0339 RealType successes,
0340 RealType probability,
0341 interval_type t = clopper_pearson_exact_interval)
0342 {
0343 static const char* function = "boost::math::binomial_distribution<%1%>::find_upper_bound_on_p";
0344
0345 RealType result = 0;
0346 if(false == binomial_detail::check_dist_and_k(
0347 function, trials, RealType(0), successes, &result, Policy())
0348 &&
0349 binomial_detail::check_dist_and_prob(
0350 function, trials, RealType(0), probability, &result, Policy()))
0351 { return result; }
0352
0353 if(trials == successes)
0354 return 1;
0355
0356 return (t == clopper_pearson_exact_interval) ? ibetac_inv(successes + 1, trials - successes, probability, static_cast<RealType*>(nullptr), Policy())
0357 : ibetac_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast<RealType*>(nullptr), Policy());
0358 }
0359
0360
0361
0362
0363
0364
0365 static RealType find_minimum_number_of_trials(
0366 RealType k,
0367 RealType p,
0368 RealType alpha)
0369 {
0370 static const char* function = "boost::math::binomial_distribution<%1%>::find_minimum_number_of_trials";
0371
0372 RealType result = 0;
0373 if(false == binomial_detail::check_dist_and_k(
0374 function, k, p, k, &result, Policy())
0375 &&
0376 binomial_detail::check_dist_and_prob(
0377 function, k, p, alpha, &result, Policy()))
0378 { return result; }
0379
0380 result = ibetac_invb(k + 1, p, alpha, Policy());
0381 return result + k;
0382 }
0383
0384 static RealType find_maximum_number_of_trials(
0385 RealType k,
0386 RealType p,
0387 RealType alpha)
0388 {
0389 static const char* function = "boost::math::binomial_distribution<%1%>::find_maximum_number_of_trials";
0390
0391 RealType result = 0;
0392 if(false == binomial_detail::check_dist_and_k(
0393 function, k, p, k, &result, Policy())
0394 &&
0395 binomial_detail::check_dist_and_prob(
0396 function, k, p, alpha, &result, Policy()))
0397 { return result; }
0398
0399 result = ibeta_invb(k + 1, p, alpha, Policy());
0400 return result + k;
0401 }
0402
0403 private:
0404 RealType m_n;
0405 RealType m_p;
0406 };
0407
0408 typedef binomial_distribution<> binomial;
0409
0410
0411
0412
0413 #ifdef __cpp_deduction_guides
0414 template <class RealType>
0415 binomial_distribution(RealType)->binomial_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0416 template <class RealType>
0417 binomial_distribution(RealType,RealType)->binomial_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0418 #endif
0419
0420 template <class RealType, class Policy>
0421 const std::pair<RealType, RealType> range(const binomial_distribution<RealType, Policy>& dist)
0422 {
0423 using boost::math::tools::max_value;
0424 return std::pair<RealType, RealType>(static_cast<RealType>(0), dist.trials());
0425 }
0426
0427 template <class RealType, class Policy>
0428 const std::pair<RealType, RealType> support(const binomial_distribution<RealType, Policy>& dist)
0429 {
0430
0431 return std::pair<RealType, RealType>(static_cast<RealType>(0), dist.trials());
0432 }
0433
0434 template <class RealType, class Policy>
0435 inline RealType mean(const binomial_distribution<RealType, Policy>& dist)
0436 {
0437 return dist.trials() * dist.success_fraction();
0438 }
0439
0440 template <class RealType, class Policy>
0441 inline RealType variance(const binomial_distribution<RealType, Policy>& dist)
0442 {
0443 return dist.trials() * dist.success_fraction() * (1 - dist.success_fraction());
0444 }
0445
0446 template <class RealType, class Policy>
0447 RealType pdf(const binomial_distribution<RealType, Policy>& dist, const RealType& k)
0448 {
0449 BOOST_FPU_EXCEPTION_GUARD
0450
0451 BOOST_MATH_STD_USING
0452
0453 RealType n = dist.trials();
0454
0455
0456 RealType result = 0;
0457 if(false == binomial_detail::check_dist_and_k(
0458 "boost::math::pdf(binomial_distribution<%1%> const&, %1%)",
0459 n,
0460 dist.success_fraction(),
0461 k,
0462 &result, Policy()))
0463 {
0464 return result;
0465 }
0466
0467
0468 if (dist.success_fraction() == 0)
0469 {
0470 return static_cast<RealType>(k == 0 ? 1 : 0);
0471 }
0472 if (dist.success_fraction() == 1)
0473 {
0474 return static_cast<RealType>(k == n ? 1 : 0);
0475 }
0476
0477
0478 if (n == 0)
0479 {
0480 return 1;
0481 }
0482 if (k == n)
0483 {
0484
0485 return pow(dist.success_fraction(), k);
0486 }
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497 using boost::math::ibeta_derivative;
0498 return ibeta_derivative(k+1, n-k+1, dist.success_fraction(), Policy()) / (n+1);
0499
0500 }
0501
0502 template <class RealType, class Policy>
0503 inline RealType cdf(const binomial_distribution<RealType, Policy>& dist, const RealType& k)
0504 {
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523 BOOST_MATH_STD_USING
0524
0525 RealType n = dist.trials();
0526 RealType p = dist.success_fraction();
0527
0528
0529 RealType result = 0;
0530 if(false == binomial_detail::check_dist_and_k(
0531 "boost::math::cdf(binomial_distribution<%1%> const&, %1%)",
0532 n,
0533 p,
0534 k,
0535 &result, Policy()))
0536 {
0537 return result;
0538 }
0539 if (k == n)
0540 {
0541 return 1;
0542 }
0543
0544
0545 if (p == 0)
0546 {
0547
0548
0549
0550
0551
0552 return 1;
0553 }
0554 if (p == 1)
0555 {
0556
0557
0558
0559 return 0;
0560 }
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571 return ibetac(k + 1, n - k, p, Policy());
0572 }
0573
0574 template <class RealType, class Policy>
0575 inline RealType cdf(const complemented2_type<binomial_distribution<RealType, Policy>, RealType>& c)
0576 {
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595 BOOST_MATH_STD_USING
0596
0597 RealType const& k = c.param;
0598 binomial_distribution<RealType, Policy> const& dist = c.dist;
0599 RealType n = dist.trials();
0600 RealType p = dist.success_fraction();
0601
0602
0603 RealType result = 0;
0604 if(false == binomial_detail::check_dist_and_k(
0605 "boost::math::cdf(binomial_distribution<%1%> const&, %1%)",
0606 n,
0607 p,
0608 k,
0609 &result, Policy()))
0610 {
0611 return result;
0612 }
0613
0614 if (k == n)
0615 {
0616 return 0;
0617 }
0618
0619
0620 if (p == 0)
0621 {
0622
0623
0624
0625
0626
0627 return 0;
0628 }
0629 if (p == 1)
0630 {
0631
0632
0633
0634
0635 return 1;
0636 }
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648 return ibeta(k + 1, n - k, p, Policy());
0649 }
0650
0651 template <class RealType, class Policy>
0652 inline RealType quantile(const binomial_distribution<RealType, Policy>& dist, const RealType& p)
0653 {
0654 return binomial_detail::quantile_imp(dist, p, RealType(1-p), false);
0655 }
0656
0657 template <class RealType, class Policy>
0658 RealType quantile(const complemented2_type<binomial_distribution<RealType, Policy>, RealType>& c)
0659 {
0660 return binomial_detail::quantile_imp(c.dist, RealType(1-c.param), c.param, true);
0661 }
0662
0663 template <class RealType, class Policy>
0664 inline RealType mode(const binomial_distribution<RealType, Policy>& dist)
0665 {
0666 BOOST_MATH_STD_USING
0667 RealType p = dist.success_fraction();
0668 RealType n = dist.trials();
0669 return floor(p * (n + 1));
0670 }
0671
0672 template <class RealType, class Policy>
0673 inline RealType median(const binomial_distribution<RealType, Policy>& dist)
0674 {
0675
0676
0677
0678
0679
0680
0681
0682
0683 BOOST_MATH_STD_USING
0684 RealType p = dist.success_fraction();
0685 RealType n = dist.trials();
0686
0687 return floor(p * n);
0688 }
0689
0690 template <class RealType, class Policy>
0691 inline RealType skewness(const binomial_distribution<RealType, Policy>& dist)
0692 {
0693 BOOST_MATH_STD_USING
0694 RealType p = dist.success_fraction();
0695 RealType n = dist.trials();
0696 return (1 - 2 * p) / sqrt(n * p * (1 - p));
0697 }
0698
0699 template <class RealType, class Policy>
0700 inline RealType kurtosis(const binomial_distribution<RealType, Policy>& dist)
0701 {
0702 RealType p = dist.success_fraction();
0703 RealType n = dist.trials();
0704 return 3 - 6 / n + 1 / (n * p * (1 - p));
0705 }
0706
0707 template <class RealType, class Policy>
0708 inline RealType kurtosis_excess(const binomial_distribution<RealType, Policy>& dist)
0709 {
0710 RealType p = dist.success_fraction();
0711 RealType q = 1 - p;
0712 RealType n = dist.trials();
0713 return (1 - 6 * p * q) / (n * p * q);
0714 }
0715
0716 }
0717 }
0718
0719
0720
0721
0722 #include <boost/math/distributions/detail/derived_accessors.hpp>
0723
0724 #endif
0725
0726