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