negative_binomial.hpp
来自「Boost provides free peer-reviewed portab」· HPP 代码 · 共 589 行 · 第 1/2 页
HPP
589 行
// boost\math\special_functions\negative_binomial.hpp// Copyright Paul A. Bristow 2007.// Copyright John Maddock 2007.// Use, modification and distribution are subject to the// Boost Software License, Version 1.0.// (See accompanying file LICENSE_1_0.txt// or copy at http://www.boost.org/LICENSE_1_0.txt)// http://en.wikipedia.org/wiki/negative_binomial_distribution// http://mathworld.wolfram.com/NegativeBinomialDistribution.html// http://documents.wolfram.com/teachersedition/Teacher/Statistics/DiscreteDistributions.html// The negative binomial distribution NegativeBinomialDistribution[n, p]// is the distribution of the number (k) of failures that occur in a sequence of trials before// r successes have occurred, where the probability of success in each trial is p.// In a sequence of Bernoulli trials or events// (independent, yes or no, succeed or fail) with success_fraction probability p,// negative_binomial is the probability that k or fewer failures// preceed the r th trial's success.// random variable k is the number of failures (NOT the probability).// Negative_binomial distribution is a discrete probability distribution.// But note that the negative binomial distribution// (like others including the binomial, Poisson & Bernoulli)// is strictly defined as a discrete function: only integral values of k are envisaged.// However because of the method of calculation using a continuous gamma function,// it is convenient to treat it as if a continous function,// and permit non-integral values of k.// However, by default the policy is to use discrete_quantile_policy.// To enforce the strict mathematical model, users should use conversion// on k outside this function to ensure that k is integral.// MATHCAD cumulative negative binomial pnbinom(k, n, p)// Implementation note: much greater speed, and perhaps greater accuracy,// might be achieved for extreme values by using a normal approximation.// This is NOT been tested or implemented.#ifndef BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP#define BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP#include <boost/math/distributions/fwd.hpp>#include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x) == Ix(a, b).#include <boost/math/distributions/complement.hpp> // complement.#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks domain_error & logic_error.#include <boost/math/special_functions/fpclassify.hpp> // isnan.#include <boost/math/tools/roots.hpp> // for root finding.#include <boost/math/distributions/detail/inv_discrete_quantile.hpp>#include <boost/type_traits/is_floating_point.hpp>#include <boost/type_traits/is_integral.hpp>#include <boost/type_traits/is_same.hpp>#include <boost/mpl/if.hpp>#include <limits> // using std::numeric_limits;#include <utility>#if defined (BOOST_MSVC)# pragma warning(push)// This believed not now necessary, so commented out.//# pragma warning(disable: 4702) // unreachable code.// in domain_error_imp in error_handling.#endifnamespace boost{ namespace math { namespace negative_binomial_detail { // Common error checking routines for negative binomial distribution functions: template <class RealType, class Policy> inline bool check_successes(const char* function, const RealType& r, RealType* result, const Policy& pol) { if( !(boost::math::isfinite)(r) || (r <= 0) ) { *result = policies::raise_domain_error<RealType>( function, "Number of successes argument is %1%, but must be > 0 !", r, pol); return false; } return true; } template <class RealType, class Policy> inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol) { if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) ) { *result = policies::raise_domain_error<RealType>( function, "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol); return false; } return true; } template <class RealType, class Policy> inline bool check_dist(const char* function, const RealType& r, const RealType& p, RealType* result, const Policy& pol) { return check_success_fraction(function, p, result, pol) && check_successes(function, r, result, pol); } template <class RealType, class Policy> inline bool check_dist_and_k(const char* function, const RealType& r, const RealType& p, RealType k, RealType* result, const Policy& pol) { if(check_dist(function, r, p, result, pol) == false) { return false; } if( !(boost::math::isfinite)(k) || (k < 0) ) { // Check k failures. *result = policies::raise_domain_error<RealType>( function, "Number of failures argument is %1%, but must be >= 0 !", k, pol); return false; } return true; } // Check_dist_and_k template <class RealType, class Policy> inline bool check_dist_and_prob(const char* function, const RealType& r, RealType p, RealType prob, RealType* result, const Policy& pol) { if(check_dist(function, r, p, result, pol) && detail::check_probability(function, prob, result, pol) == false) { return false; } return true; } // check_dist_and_prob } // namespace negative_binomial_detail template <class RealType = double, class Policy = policies::policy<> > class negative_binomial_distribution { public: typedef RealType value_type; typedef Policy policy_type; negative_binomial_distribution(RealType r, RealType p) : m_r(r), m_p(p) { // Constructor. RealType result; negative_binomial_detail::check_dist( "negative_binomial_distribution<%1%>::negative_binomial_distribution", m_r, // Check successes r > 0. m_p, // Check success_fraction 0 <= p <= 1. &result, Policy()); } // negative_binomial_distribution constructor. // Private data getter class member functions. RealType success_fraction() const { // Probability of success as fraction in range 0 to 1. return m_p; } RealType successes() const { // Total number of successes r. return m_r; } static RealType find_lower_bound_on_p( RealType trials, RealType successes, RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test. { static const char* function = "boost::math::negative_binomial<%1%>::find_lower_bound_on_p"; RealType result; // of error checks. RealType failures = trials - successes; if(false == detail::check_probability(function, alpha, &result, Policy()) && negative_binomial_detail::check_dist_and_k( function, successes, RealType(0), failures, &result, Policy())) { return result; } // Use complement ibeta_inv function for lower bound. // This is adapted from the corresponding binomial formula // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm // This is a Clopper-Pearson interval, and may be overly conservative, // see also "A Simple Improved Inferential Method for Some // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf // return ibeta_inv(successes, failures + 1, alpha, static_cast<RealType*>(0), Policy()); } // find_lower_bound_on_p static RealType find_upper_bound_on_p( RealType trials, RealType successes, RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test. { static const char* function = "boost::math::negative_binomial<%1%>::find_upper_bound_on_p"; RealType result; // of error checks. RealType failures = trials - successes; if(false == negative_binomial_detail::check_dist_and_k( function, successes, RealType(0), failures, &result, Policy()) && detail::check_probability(function, alpha, &result, Policy())) { return result; } if(failures == 0) return 1; // Use complement ibetac_inv function for upper bound. // Note adjusted failures value: *not* failures+1 as usual. // This is adapted from the corresponding binomial formula // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm // This is a Clopper-Pearson interval, and may be overly conservative, // see also "A Simple Improved Inferential Method for Some // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf // return ibetac_inv(successes, failures, alpha, static_cast<RealType*>(0), Policy()); } // find_upper_bound_on_p // Estimate number of trials : // "How many trials do I need to be P% sure of seeing k or fewer failures?" static RealType find_minimum_number_of_trials( RealType k, // number of failures (k >= 0). RealType p, // success fraction 0 <= p <= 1. RealType alpha) // risk level threshold 0 <= alpha <= 1. { static const char* function = "boost::math::negative_binomial<%1%>::find_minimum_number_of_trials"; // Error checks: RealType result; if(false == negative_binomial_detail::check_dist_and_k( function, RealType(1), p, k, &result, Policy()) && detail::check_probability(function, alpha, &result, Policy())) { return result; } result = ibeta_inva(k + 1, p, alpha, Policy()); // returns n - k return result + k; } // RealType find_number_of_failures static RealType find_maximum_number_of_trials( RealType k, // number of failures (k >= 0). RealType p, // success fraction 0 <= p <= 1. RealType alpha) // risk level threshold 0 <= alpha <= 1. { static const char* function = "boost::math::negative_binomial<%1%>::find_maximum_number_of_trials"; // Error checks: RealType result; if(false == negative_binomial_detail::check_dist_and_k( function, RealType(1), p, k, &result, Policy()) && detail::check_probability(function, alpha, &result, Policy())) { return result; } result = ibetac_inva(k + 1, p, alpha, Policy()); // returns n - k return result + k; } // RealType find_number_of_trials complemented private: RealType m_r; // successes. RealType m_p; // success_fraction }; // template <class RealType, class Policy> class negative_binomial_distribution typedef negative_binomial_distribution<double> negative_binomial; // Reserved name of type double. template <class RealType, class Policy> inline const std::pair<RealType, RealType> range(const negative_binomial_distribution<RealType, Policy>& /* dist */) { // Range of permissible values for random variable k. using boost::math::tools::max_value; return std::pair<RealType, RealType>(0, max_value<RealType>()); // max_integer? } template <class RealType, class Policy> inline const std::pair<RealType, RealType> support(const negative_binomial_distribution<RealType, Policy>& /* dist */) { // Range of supported values for random variable k. // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. using boost::math::tools::max_value; return std::pair<RealType, RealType>(0, max_value<RealType>()); // max_integer? } template <class RealType, class Policy> inline RealType mean(const negative_binomial_distribution<RealType, Policy>& dist) { // Mean of Negative Binomial distribution = r(1-p)/p. return dist.successes() * (1 - dist.success_fraction() ) / dist.success_fraction(); } // mean //template <class RealType, class Policy> //inline RealType median(const negative_binomial_distribution<RealType, Policy>& dist) //{ // Median of negative_binomial_distribution is not defined. // return policies::raise_domain_error<RealType>(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN()); //} // median // Now implemented via quantile(half) in derived accessors. template <class RealType, class Policy> inline RealType mode(const negative_binomial_distribution<RealType, Policy>& dist) { // Mode of Negative Binomial distribution = floor[(r-1) * (1 - p)/p] BOOST_MATH_STD_USING // ADL of std functions. return floor((dist.successes() -1) * (1 - dist.success_fraction()) / dist.success_fraction()); } // mode template <class RealType, class Policy> inline RealType skewness(const negative_binomial_distribution<RealType, Policy>& dist)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?