File indexing completed on 2025-07-11 08:14:56
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 result = 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 return result;
0271 }
0272
0273 }
0274
0275 template <class RealType = double, class Policy = policies::policy<> >
0276 class binomial_distribution
0277 {
0278 public:
0279 typedef RealType value_type;
0280 typedef Policy policy_type;
0281
0282 binomial_distribution(RealType n = 1, RealType p = 0.5) : m_n(n), m_p(p)
0283 {
0284
0285 RealType r;
0286 binomial_detail::check_dist(
0287 "boost::math::binomial_distribution<%1%>::binomial_distribution",
0288 m_n,
0289 m_p,
0290 &r, Policy());
0291 }
0292
0293 RealType success_fraction() const
0294 {
0295 return m_p;
0296 }
0297 RealType trials() const
0298 {
0299 return m_n;
0300 }
0301
0302 enum interval_type{
0303 clopper_pearson_exact_interval,
0304 jeffreys_prior_interval
0305 };
0306
0307
0308
0309
0310
0311
0312
0313 static RealType find_lower_bound_on_p(
0314 RealType trials,
0315 RealType successes,
0316 RealType probability,
0317 interval_type t = clopper_pearson_exact_interval)
0318 {
0319 static const char* function = "boost::math::binomial_distribution<%1%>::find_lower_bound_on_p";
0320
0321 RealType result = 0;
0322 if(false == binomial_detail::check_dist_and_k(
0323 function, trials, RealType(0), successes, &result, Policy())
0324 &&
0325 binomial_detail::check_dist_and_prob(
0326 function, trials, RealType(0), probability, &result, Policy()))
0327 { return result; }
0328
0329 if(successes == 0)
0330 return 0;
0331
0332
0333
0334
0335 return (t == clopper_pearson_exact_interval) ? ibeta_inv(successes, trials - successes + 1, probability, static_cast<RealType*>(nullptr), Policy())
0336 : ibeta_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast<RealType*>(nullptr), Policy());
0337 }
0338 static RealType find_upper_bound_on_p(
0339 RealType trials,
0340 RealType successes,
0341 RealType probability,
0342 interval_type t = clopper_pearson_exact_interval)
0343 {
0344 static const char* function = "boost::math::binomial_distribution<%1%>::find_upper_bound_on_p";
0345
0346 RealType result = 0;
0347 if(false == binomial_detail::check_dist_and_k(
0348 function, trials, RealType(0), successes, &result, Policy())
0349 &&
0350 binomial_detail::check_dist_and_prob(
0351 function, trials, RealType(0), probability, &result, Policy()))
0352 { return result; }
0353
0354 if(trials == successes)
0355 return 1;
0356
0357 return (t == clopper_pearson_exact_interval) ? ibetac_inv(successes + 1, trials - successes, probability, static_cast<RealType*>(nullptr), Policy())
0358 : ibetac_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast<RealType*>(nullptr), Policy());
0359 }
0360
0361
0362
0363
0364
0365
0366 static RealType find_minimum_number_of_trials(
0367 RealType k,
0368 RealType p,
0369 RealType alpha)
0370 {
0371 static const char* function = "boost::math::binomial_distribution<%1%>::find_minimum_number_of_trials";
0372
0373 RealType result = 0;
0374 if(false == binomial_detail::check_dist_and_k(
0375 function, k, p, k, &result, Policy())
0376 &&
0377 binomial_detail::check_dist_and_prob(
0378 function, k, p, alpha, &result, Policy()))
0379 { return result; }
0380
0381 result = ibetac_invb(k + 1, p, alpha, Policy());
0382 return result + k;
0383 }
0384
0385 static RealType find_maximum_number_of_trials(
0386 RealType k,
0387 RealType p,
0388 RealType alpha)
0389 {
0390 static const char* function = "boost::math::binomial_distribution<%1%>::find_maximum_number_of_trials";
0391
0392 RealType result = 0;
0393 if(false == binomial_detail::check_dist_and_k(
0394 function, k, p, k, &result, Policy())
0395 &&
0396 binomial_detail::check_dist_and_prob(
0397 function, k, p, alpha, &result, Policy()))
0398 { return result; }
0399
0400 result = ibeta_invb(k + 1, p, alpha, Policy());
0401 return result + k;
0402 }
0403
0404 private:
0405 RealType m_n;
0406 RealType m_p;
0407 };
0408
0409 typedef binomial_distribution<> binomial;
0410
0411
0412
0413
0414 #ifdef __cpp_deduction_guides
0415 template <class RealType>
0416 binomial_distribution(RealType)->binomial_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0417 template <class RealType>
0418 binomial_distribution(RealType,RealType)->binomial_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0419 #endif
0420
0421 template <class RealType, class Policy>
0422 const std::pair<RealType, RealType> range(const binomial_distribution<RealType, Policy>& dist)
0423 {
0424 using boost::math::tools::max_value;
0425 return std::pair<RealType, RealType>(static_cast<RealType>(0), dist.trials());
0426 }
0427
0428 template <class RealType, class Policy>
0429 const std::pair<RealType, RealType> support(const binomial_distribution<RealType, Policy>& dist)
0430 {
0431
0432 return std::pair<RealType, RealType>(static_cast<RealType>(0), dist.trials());
0433 }
0434
0435 template <class RealType, class Policy>
0436 inline RealType mean(const binomial_distribution<RealType, Policy>& dist)
0437 {
0438 return dist.trials() * dist.success_fraction();
0439 }
0440
0441 template <class RealType, class Policy>
0442 inline RealType variance(const binomial_distribution<RealType, Policy>& dist)
0443 {
0444 return dist.trials() * dist.success_fraction() * (1 - dist.success_fraction());
0445 }
0446
0447 template <class RealType, class Policy>
0448 RealType pdf(const binomial_distribution<RealType, Policy>& dist, const RealType& k)
0449 {
0450 BOOST_FPU_EXCEPTION_GUARD
0451
0452 BOOST_MATH_STD_USING
0453
0454 RealType n = dist.trials();
0455
0456
0457 RealType result = 0;
0458 if(false == binomial_detail::check_dist_and_k(
0459 "boost::math::pdf(binomial_distribution<%1%> const&, %1%)",
0460 n,
0461 dist.success_fraction(),
0462 k,
0463 &result, Policy()))
0464 {
0465 return result;
0466 }
0467
0468
0469 if (dist.success_fraction() == 0)
0470 {
0471 return static_cast<RealType>(k == 0 ? 1 : 0);
0472 }
0473 if (dist.success_fraction() == 1)
0474 {
0475 return static_cast<RealType>(k == n ? 1 : 0);
0476 }
0477
0478
0479 if (n == 0)
0480 {
0481 return 1;
0482 }
0483 if (k == n)
0484 {
0485
0486 return pow(dist.success_fraction(), k);
0487 }
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498 using boost::math::ibeta_derivative;
0499 return ibeta_derivative(k+1, n-k+1, dist.success_fraction(), Policy()) / (n+1);
0500
0501 }
0502
0503 template <class RealType, class Policy>
0504 inline RealType cdf(const binomial_distribution<RealType, Policy>& dist, const RealType& k)
0505 {
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524 BOOST_MATH_STD_USING
0525
0526 RealType n = dist.trials();
0527 RealType p = dist.success_fraction();
0528
0529
0530 RealType result = 0;
0531 if(false == binomial_detail::check_dist_and_k(
0532 "boost::math::cdf(binomial_distribution<%1%> const&, %1%)",
0533 n,
0534 p,
0535 k,
0536 &result, Policy()))
0537 {
0538 return result;
0539 }
0540 if (k == n)
0541 {
0542 return 1;
0543 }
0544
0545
0546 if (p == 0)
0547 {
0548
0549
0550
0551
0552
0553 return 1;
0554 }
0555 if (p == 1)
0556 {
0557
0558
0559
0560 return 0;
0561 }
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572 return ibetac(k + 1, n - k, p, Policy());
0573 }
0574
0575 template <class RealType, class Policy>
0576 inline RealType cdf(const complemented2_type<binomial_distribution<RealType, Policy>, RealType>& c)
0577 {
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596 BOOST_MATH_STD_USING
0597
0598 RealType const& k = c.param;
0599 binomial_distribution<RealType, Policy> const& dist = c.dist;
0600 RealType n = dist.trials();
0601 RealType p = dist.success_fraction();
0602
0603
0604 RealType result = 0;
0605 if(false == binomial_detail::check_dist_and_k(
0606 "boost::math::cdf(binomial_distribution<%1%> const&, %1%)",
0607 n,
0608 p,
0609 k,
0610 &result, Policy()))
0611 {
0612 return result;
0613 }
0614
0615 if (k == n)
0616 {
0617 return 0;
0618 }
0619
0620
0621 if (p == 0)
0622 {
0623
0624
0625
0626
0627
0628 return 0;
0629 }
0630 if (p == 1)
0631 {
0632
0633
0634
0635
0636 return 1;
0637 }
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649 return ibeta(k + 1, n - k, p, Policy());
0650 }
0651
0652 template <class RealType, class Policy>
0653 inline RealType quantile(const binomial_distribution<RealType, Policy>& dist, const RealType& p)
0654 {
0655 return binomial_detail::quantile_imp(dist, p, RealType(1-p), false);
0656 }
0657
0658 template <class RealType, class Policy>
0659 RealType quantile(const complemented2_type<binomial_distribution<RealType, Policy>, RealType>& c)
0660 {
0661 return binomial_detail::quantile_imp(c.dist, RealType(1-c.param), c.param, true);
0662 }
0663
0664 template <class RealType, class Policy>
0665 inline RealType mode(const binomial_distribution<RealType, Policy>& dist)
0666 {
0667 BOOST_MATH_STD_USING
0668 RealType p = dist.success_fraction();
0669 RealType n = dist.trials();
0670 return floor(p * (n + 1));
0671 }
0672
0673 template <class RealType, class Policy>
0674 inline RealType median(const binomial_distribution<RealType, Policy>& dist)
0675 {
0676
0677
0678
0679
0680
0681
0682
0683
0684 BOOST_MATH_STD_USING
0685 RealType p = dist.success_fraction();
0686 RealType n = dist.trials();
0687
0688 return floor(p * n);
0689 }
0690
0691 template <class RealType, class Policy>
0692 inline RealType skewness(const binomial_distribution<RealType, Policy>& dist)
0693 {
0694 BOOST_MATH_STD_USING
0695 RealType p = dist.success_fraction();
0696 RealType n = dist.trials();
0697 return (1 - 2 * p) / sqrt(n * p * (1 - p));
0698 }
0699
0700 template <class RealType, class Policy>
0701 inline RealType kurtosis(const binomial_distribution<RealType, Policy>& dist)
0702 {
0703 RealType p = dist.success_fraction();
0704 RealType n = dist.trials();
0705 return 3 - 6 / n + 1 / (n * p * (1 - p));
0706 }
0707
0708 template <class RealType, class Policy>
0709 inline RealType kurtosis_excess(const binomial_distribution<RealType, Policy>& dist)
0710 {
0711 RealType p = dist.success_fraction();
0712 RealType q = 1 - p;
0713 RealType n = dist.trials();
0714 return (1 - 6 * p * q) / (n * p * q);
0715 }
0716
0717 }
0718 }
0719
0720
0721
0722
0723 #include <boost/math/distributions/detail/derived_accessors.hpp>
0724
0725 #endif
0726
0727