annotate any/include/boost/math/distributions/geometric.hpp @ 160:cff480c41f97

Add some cross-platform Boost headers
author Chris Cannam <cannam@all-day-breakfast.com>
date Sat, 16 Feb 2019 16:31:25 +0000
parents
children
rev   line source
cannam@160 1 // boost\math\distributions\geometric.hpp
cannam@160 2
cannam@160 3 // Copyright John Maddock 2010.
cannam@160 4 // Copyright Paul A. Bristow 2010.
cannam@160 5
cannam@160 6 // Use, modification and distribution are subject to the
cannam@160 7 // Boost Software License, Version 1.0.
cannam@160 8 // (See accompanying file LICENSE_1_0.txt
cannam@160 9 // or copy at http://www.boost.org/LICENSE_1_0.txt)
cannam@160 10
cannam@160 11 // geometric distribution is a discrete probability distribution.
cannam@160 12 // It expresses the probability distribution of the number (k) of
cannam@160 13 // events, occurrences, failures or arrivals before the first success.
cannam@160 14 // supported on the set {0, 1, 2, 3...}
cannam@160 15
cannam@160 16 // Note that the set includes zero (unlike some definitions that start at one).
cannam@160 17
cannam@160 18 // The random variate k is the number of events, occurrences or arrivals.
cannam@160 19 // k argument may be integral, signed, or unsigned, or floating point.
cannam@160 20 // If necessary, it has already been promoted from an integral type.
cannam@160 21
cannam@160 22 // Note that the geometric distribution
cannam@160 23 // (like others including the binomial, geometric & Bernoulli)
cannam@160 24 // is strictly defined as a discrete function:
cannam@160 25 // only integral values of k are envisaged.
cannam@160 26 // However because the method of calculation uses a continuous gamma function,
cannam@160 27 // it is convenient to treat it as if a continous function,
cannam@160 28 // and permit non-integral values of k.
cannam@160 29 // To enforce the strict mathematical model, users should use floor or ceil functions
cannam@160 30 // on k outside this function to ensure that k is integral.
cannam@160 31
cannam@160 32 // See http://en.wikipedia.org/wiki/geometric_distribution
cannam@160 33 // http://documents.wolfram.com/v5/Add-onsLinks/StandardPackages/Statistics/DiscreteDistributions.html
cannam@160 34 // http://mathworld.wolfram.com/GeometricDistribution.html
cannam@160 35
cannam@160 36 #ifndef BOOST_MATH_SPECIAL_GEOMETRIC_HPP
cannam@160 37 #define BOOST_MATH_SPECIAL_GEOMETRIC_HPP
cannam@160 38
cannam@160 39 #include <boost/math/distributions/fwd.hpp>
cannam@160 40 #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x) == Ix(a, b).
cannam@160 41 #include <boost/math/distributions/complement.hpp> // complement.
cannam@160 42 #include <boost/math/distributions/detail/common_error_handling.hpp> // error checks domain_error & logic_error.
cannam@160 43 #include <boost/math/special_functions/fpclassify.hpp> // isnan.
cannam@160 44 #include <boost/math/tools/roots.hpp> // for root finding.
cannam@160 45 #include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
cannam@160 46
cannam@160 47 #include <boost/type_traits/is_floating_point.hpp>
cannam@160 48 #include <boost/type_traits/is_integral.hpp>
cannam@160 49 #include <boost/type_traits/is_same.hpp>
cannam@160 50 #include <boost/mpl/if.hpp>
cannam@160 51
cannam@160 52 #include <limits> // using std::numeric_limits;
cannam@160 53 #include <utility>
cannam@160 54
cannam@160 55 #if defined (BOOST_MSVC)
cannam@160 56 # pragma warning(push)
cannam@160 57 // This believed not now necessary, so commented out.
cannam@160 58 //# pragma warning(disable: 4702) // unreachable code.
cannam@160 59 // in domain_error_imp in error_handling.
cannam@160 60 #endif
cannam@160 61
cannam@160 62 namespace boost
cannam@160 63 {
cannam@160 64 namespace math
cannam@160 65 {
cannam@160 66 namespace geometric_detail
cannam@160 67 {
cannam@160 68 // Common error checking routines for geometric distribution function:
cannam@160 69 template <class RealType, class Policy>
cannam@160 70 inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
cannam@160 71 {
cannam@160 72 if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) )
cannam@160 73 {
cannam@160 74 *result = policies::raise_domain_error<RealType>(
cannam@160 75 function,
cannam@160 76 "Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
cannam@160 77 return false;
cannam@160 78 }
cannam@160 79 return true;
cannam@160 80 }
cannam@160 81
cannam@160 82 template <class RealType, class Policy>
cannam@160 83 inline bool check_dist(const char* function, const RealType& p, RealType* result, const Policy& pol)
cannam@160 84 {
cannam@160 85 return check_success_fraction(function, p, result, pol);
cannam@160 86 }
cannam@160 87
cannam@160 88 template <class RealType, class Policy>
cannam@160 89 inline bool check_dist_and_k(const char* function, const RealType& p, RealType k, RealType* result, const Policy& pol)
cannam@160 90 {
cannam@160 91 if(check_dist(function, p, result, pol) == false)
cannam@160 92 {
cannam@160 93 return false;
cannam@160 94 }
cannam@160 95 if( !(boost::math::isfinite)(k) || (k < 0) )
cannam@160 96 { // Check k failures.
cannam@160 97 *result = policies::raise_domain_error<RealType>(
cannam@160 98 function,
cannam@160 99 "Number of failures argument is %1%, but must be >= 0 !", k, pol);
cannam@160 100 return false;
cannam@160 101 }
cannam@160 102 return true;
cannam@160 103 } // Check_dist_and_k
cannam@160 104
cannam@160 105 template <class RealType, class Policy>
cannam@160 106 inline bool check_dist_and_prob(const char* function, RealType p, RealType prob, RealType* result, const Policy& pol)
cannam@160 107 {
cannam@160 108 if((check_dist(function, p, result, pol) && detail::check_probability(function, prob, result, pol)) == false)
cannam@160 109 {
cannam@160 110 return false;
cannam@160 111 }
cannam@160 112 return true;
cannam@160 113 } // check_dist_and_prob
cannam@160 114 } // namespace geometric_detail
cannam@160 115
cannam@160 116 template <class RealType = double, class Policy = policies::policy<> >
cannam@160 117 class geometric_distribution
cannam@160 118 {
cannam@160 119 public:
cannam@160 120 typedef RealType value_type;
cannam@160 121 typedef Policy policy_type;
cannam@160 122
cannam@160 123 geometric_distribution(RealType p) : m_p(p)
cannam@160 124 { // Constructor stores success_fraction p.
cannam@160 125 RealType result;
cannam@160 126 geometric_detail::check_dist(
cannam@160 127 "geometric_distribution<%1%>::geometric_distribution",
cannam@160 128 m_p, // Check success_fraction 0 <= p <= 1.
cannam@160 129 &result, Policy());
cannam@160 130 } // geometric_distribution constructor.
cannam@160 131
cannam@160 132 // Private data getter class member functions.
cannam@160 133 RealType success_fraction() const
cannam@160 134 { // Probability of success as fraction in range 0 to 1.
cannam@160 135 return m_p;
cannam@160 136 }
cannam@160 137 RealType successes() const
cannam@160 138 { // Total number of successes r = 1 (for compatibility with negative binomial?).
cannam@160 139 return 1;
cannam@160 140 }
cannam@160 141
cannam@160 142 // Parameter estimation.
cannam@160 143 // (These are copies of negative_binomial distribution with successes = 1).
cannam@160 144 static RealType find_lower_bound_on_p(
cannam@160 145 RealType trials,
cannam@160 146 RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
cannam@160 147 {
cannam@160 148 static const char* function = "boost::math::geometric<%1%>::find_lower_bound_on_p";
cannam@160 149 RealType result = 0; // of error checks.
cannam@160 150 RealType successes = 1;
cannam@160 151 RealType failures = trials - successes;
cannam@160 152 if(false == detail::check_probability(function, alpha, &result, Policy())
cannam@160 153 && geometric_detail::check_dist_and_k(
cannam@160 154 function, RealType(0), failures, &result, Policy()))
cannam@160 155 {
cannam@160 156 return result;
cannam@160 157 }
cannam@160 158 // Use complement ibeta_inv function for lower bound.
cannam@160 159 // This is adapted from the corresponding binomial formula
cannam@160 160 // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
cannam@160 161 // This is a Clopper-Pearson interval, and may be overly conservative,
cannam@160 162 // see also "A Simple Improved Inferential Method for Some
cannam@160 163 // Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
cannam@160 164 // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
cannam@160 165 //
cannam@160 166 return ibeta_inv(successes, failures + 1, alpha, static_cast<RealType*>(0), Policy());
cannam@160 167 } // find_lower_bound_on_p
cannam@160 168
cannam@160 169 static RealType find_upper_bound_on_p(
cannam@160 170 RealType trials,
cannam@160 171 RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
cannam@160 172 {
cannam@160 173 static const char* function = "boost::math::geometric<%1%>::find_upper_bound_on_p";
cannam@160 174 RealType result = 0; // of error checks.
cannam@160 175 RealType successes = 1;
cannam@160 176 RealType failures = trials - successes;
cannam@160 177 if(false == geometric_detail::check_dist_and_k(
cannam@160 178 function, RealType(0), failures, &result, Policy())
cannam@160 179 && detail::check_probability(function, alpha, &result, Policy()))
cannam@160 180 {
cannam@160 181 return result;
cannam@160 182 }
cannam@160 183 if(failures == 0)
cannam@160 184 {
cannam@160 185 return 1;
cannam@160 186 }// Use complement ibetac_inv function for upper bound.
cannam@160 187 // Note adjusted failures value: *not* failures+1 as usual.
cannam@160 188 // This is adapted from the corresponding binomial formula
cannam@160 189 // here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
cannam@160 190 // This is a Clopper-Pearson interval, and may be overly conservative,
cannam@160 191 // see also "A Simple Improved Inferential Method for Some
cannam@160 192 // Discrete Distributions" Yong CAI and K. Krishnamoorthy
cannam@160 193 // http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
cannam@160 194 //
cannam@160 195 return ibetac_inv(successes, failures, alpha, static_cast<RealType*>(0), Policy());
cannam@160 196 } // find_upper_bound_on_p
cannam@160 197
cannam@160 198 // Estimate number of trials :
cannam@160 199 // "How many trials do I need to be P% sure of seeing k or fewer failures?"
cannam@160 200
cannam@160 201 static RealType find_minimum_number_of_trials(
cannam@160 202 RealType k, // number of failures (k >= 0).
cannam@160 203 RealType p, // success fraction 0 <= p <= 1.
cannam@160 204 RealType alpha) // risk level threshold 0 <= alpha <= 1.
cannam@160 205 {
cannam@160 206 static const char* function = "boost::math::geometric<%1%>::find_minimum_number_of_trials";
cannam@160 207 // Error checks:
cannam@160 208 RealType result = 0;
cannam@160 209 if(false == geometric_detail::check_dist_and_k(
cannam@160 210 function, p, k, &result, Policy())
cannam@160 211 && detail::check_probability(function, alpha, &result, Policy()))
cannam@160 212 {
cannam@160 213 return result;
cannam@160 214 }
cannam@160 215 result = ibeta_inva(k + 1, p, alpha, Policy()); // returns n - k
cannam@160 216 return result + k;
cannam@160 217 } // RealType find_number_of_failures
cannam@160 218
cannam@160 219 static RealType find_maximum_number_of_trials(
cannam@160 220 RealType k, // number of failures (k >= 0).
cannam@160 221 RealType p, // success fraction 0 <= p <= 1.
cannam@160 222 RealType alpha) // risk level threshold 0 <= alpha <= 1.
cannam@160 223 {
cannam@160 224 static const char* function = "boost::math::geometric<%1%>::find_maximum_number_of_trials";
cannam@160 225 // Error checks:
cannam@160 226 RealType result = 0;
cannam@160 227 if(false == geometric_detail::check_dist_and_k(
cannam@160 228 function, p, k, &result, Policy())
cannam@160 229 && detail::check_probability(function, alpha, &result, Policy()))
cannam@160 230 {
cannam@160 231 return result;
cannam@160 232 }
cannam@160 233 result = ibetac_inva(k + 1, p, alpha, Policy()); // returns n - k
cannam@160 234 return result + k;
cannam@160 235 } // RealType find_number_of_trials complemented
cannam@160 236
cannam@160 237 private:
cannam@160 238 //RealType m_r; // successes fixed at unity.
cannam@160 239 RealType m_p; // success_fraction
cannam@160 240 }; // template <class RealType, class Policy> class geometric_distribution
cannam@160 241
cannam@160 242 typedef geometric_distribution<double> geometric; // Reserved name of type double.
cannam@160 243
cannam@160 244 template <class RealType, class Policy>
cannam@160 245 inline const std::pair<RealType, RealType> range(const geometric_distribution<RealType, Policy>& /* dist */)
cannam@160 246 { // Range of permissible values for random variable k.
cannam@160 247 using boost::math::tools::max_value;
cannam@160 248 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // max_integer?
cannam@160 249 }
cannam@160 250
cannam@160 251 template <class RealType, class Policy>
cannam@160 252 inline const std::pair<RealType, RealType> support(const geometric_distribution<RealType, Policy>& /* dist */)
cannam@160 253 { // Range of supported values for random variable k.
cannam@160 254 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
cannam@160 255 using boost::math::tools::max_value;
cannam@160 256 return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>()); // max_integer?
cannam@160 257 }
cannam@160 258
cannam@160 259 template <class RealType, class Policy>
cannam@160 260 inline RealType mean(const geometric_distribution<RealType, Policy>& dist)
cannam@160 261 { // Mean of geometric distribution = (1-p)/p.
cannam@160 262 return (1 - dist.success_fraction() ) / dist.success_fraction();
cannam@160 263 } // mean
cannam@160 264
cannam@160 265 // median implemented via quantile(half) in derived accessors.
cannam@160 266
cannam@160 267 template <class RealType, class Policy>
cannam@160 268 inline RealType mode(const geometric_distribution<RealType, Policy>&)
cannam@160 269 { // Mode of geometric distribution = zero.
cannam@160 270 BOOST_MATH_STD_USING // ADL of std functions.
cannam@160 271 return 0;
cannam@160 272 } // mode
cannam@160 273
cannam@160 274 template <class RealType, class Policy>
cannam@160 275 inline RealType variance(const geometric_distribution<RealType, Policy>& dist)
cannam@160 276 { // Variance of Binomial distribution = (1-p) / p^2.
cannam@160 277 return (1 - dist.success_fraction())
cannam@160 278 / (dist.success_fraction() * dist.success_fraction());
cannam@160 279 } // variance
cannam@160 280
cannam@160 281 template <class RealType, class Policy>
cannam@160 282 inline RealType skewness(const geometric_distribution<RealType, Policy>& dist)
cannam@160 283 { // skewness of geometric distribution = 2-p / (sqrt(r(1-p))
cannam@160 284 BOOST_MATH_STD_USING // ADL of std functions.
cannam@160 285 RealType p = dist.success_fraction();
cannam@160 286 return (2 - p) / sqrt(1 - p);
cannam@160 287 } // skewness
cannam@160 288
cannam@160 289 template <class RealType, class Policy>
cannam@160 290 inline RealType kurtosis(const geometric_distribution<RealType, Policy>& dist)
cannam@160 291 { // kurtosis of geometric distribution
cannam@160 292 // http://en.wikipedia.org/wiki/geometric is kurtosis_excess so add 3
cannam@160 293 RealType p = dist.success_fraction();
cannam@160 294 return 3 + (p*p - 6*p + 6) / (1 - p);
cannam@160 295 } // kurtosis
cannam@160 296
cannam@160 297 template <class RealType, class Policy>
cannam@160 298 inline RealType kurtosis_excess(const geometric_distribution<RealType, Policy>& dist)
cannam@160 299 { // kurtosis excess of geometric distribution
cannam@160 300 // http://mathworld.wolfram.com/Kurtosis.html table of kurtosis_excess
cannam@160 301 RealType p = dist.success_fraction();
cannam@160 302 return (p*p - 6*p + 6) / (1 - p);
cannam@160 303 } // kurtosis_excess
cannam@160 304
cannam@160 305 // RealType standard_deviation(const geometric_distribution<RealType, Policy>& dist)
cannam@160 306 // standard_deviation provided by derived accessors.
cannam@160 307 // RealType hazard(const geometric_distribution<RealType, Policy>& dist)
cannam@160 308 // hazard of geometric distribution provided by derived accessors.
cannam@160 309 // RealType chf(const geometric_distribution<RealType, Policy>& dist)
cannam@160 310 // chf of geometric distribution provided by derived accessors.
cannam@160 311
cannam@160 312 template <class RealType, class Policy>
cannam@160 313 inline RealType pdf(const geometric_distribution<RealType, Policy>& dist, const RealType& k)
cannam@160 314 { // Probability Density/Mass Function.
cannam@160 315 BOOST_FPU_EXCEPTION_GUARD
cannam@160 316 BOOST_MATH_STD_USING // For ADL of math functions.
cannam@160 317 static const char* function = "boost::math::pdf(const geometric_distribution<%1%>&, %1%)";
cannam@160 318
cannam@160 319 RealType p = dist.success_fraction();
cannam@160 320 RealType result = 0;
cannam@160 321 if(false == geometric_detail::check_dist_and_k(
cannam@160 322 function,
cannam@160 323 p,
cannam@160 324 k,
cannam@160 325 &result, Policy()))
cannam@160 326 {
cannam@160 327 return result;
cannam@160 328 }
cannam@160 329 if (k == 0)
cannam@160 330 {
cannam@160 331 return p; // success_fraction
cannam@160 332 }
cannam@160 333 RealType q = 1 - p; // Inaccurate for small p?
cannam@160 334 // So try to avoid inaccuracy for large or small p.
cannam@160 335 // but has little effect > last significant bit.
cannam@160 336 //cout << "p * pow(q, k) " << result << endl; // seems best whatever p
cannam@160 337 //cout << "exp(p * k * log1p(-p)) " << p * exp(k * log1p(-p)) << endl;
cannam@160 338 //if (p < 0.5)
cannam@160 339 //{
cannam@160 340 // result = p * pow(q, k);
cannam@160 341 //}
cannam@160 342 //else
cannam@160 343 //{
cannam@160 344 // result = p * exp(k * log1p(-p));
cannam@160 345 //}
cannam@160 346 result = p * pow(q, k);
cannam@160 347 return result;
cannam@160 348 } // geometric_pdf
cannam@160 349
cannam@160 350 template <class RealType, class Policy>
cannam@160 351 inline RealType cdf(const geometric_distribution<RealType, Policy>& dist, const RealType& k)
cannam@160 352 { // Cumulative Distribution Function of geometric.
cannam@160 353 static const char* function = "boost::math::cdf(const geometric_distribution<%1%>&, %1%)";
cannam@160 354
cannam@160 355 // k argument may be integral, signed, or unsigned, or floating point.
cannam@160 356 // If necessary, it has already been promoted from an integral type.
cannam@160 357 RealType p = dist.success_fraction();
cannam@160 358 // Error check:
cannam@160 359 RealType result = 0;
cannam@160 360 if(false == geometric_detail::check_dist_and_k(
cannam@160 361 function,
cannam@160 362 p,
cannam@160 363 k,
cannam@160 364 &result, Policy()))
cannam@160 365 {
cannam@160 366 return result;
cannam@160 367 }
cannam@160 368 if(k == 0)
cannam@160 369 {
cannam@160 370 return p; // success_fraction
cannam@160 371 }
cannam@160 372 //RealType q = 1 - p; // Bad for small p
cannam@160 373 //RealType probability = 1 - std::pow(q, k+1);
cannam@160 374
cannam@160 375 RealType z = boost::math::log1p(-p, Policy()) * (k + 1);
cannam@160 376 RealType probability = -boost::math::expm1(z, Policy());
cannam@160 377
cannam@160 378 return probability;
cannam@160 379 } // cdf Cumulative Distribution Function geometric.
cannam@160 380
cannam@160 381 template <class RealType, class Policy>
cannam@160 382 inline RealType cdf(const complemented2_type<geometric_distribution<RealType, Policy>, RealType>& c)
cannam@160 383 { // Complemented Cumulative Distribution Function geometric.
cannam@160 384 BOOST_MATH_STD_USING
cannam@160 385 static const char* function = "boost::math::cdf(const geometric_distribution<%1%>&, %1%)";
cannam@160 386 // k argument may be integral, signed, or unsigned, or floating point.
cannam@160 387 // If necessary, it has already been promoted from an integral type.
cannam@160 388 RealType const& k = c.param;
cannam@160 389 geometric_distribution<RealType, Policy> const& dist = c.dist;
cannam@160 390 RealType p = dist.success_fraction();
cannam@160 391 // Error check:
cannam@160 392 RealType result = 0;
cannam@160 393 if(false == geometric_detail::check_dist_and_k(
cannam@160 394 function,
cannam@160 395 p,
cannam@160 396 k,
cannam@160 397 &result, Policy()))
cannam@160 398 {
cannam@160 399 return result;
cannam@160 400 }
cannam@160 401 RealType z = boost::math::log1p(-p, Policy()) * (k+1);
cannam@160 402 RealType probability = exp(z);
cannam@160 403 return probability;
cannam@160 404 } // cdf Complemented Cumulative Distribution Function geometric.
cannam@160 405
cannam@160 406 template <class RealType, class Policy>
cannam@160 407 inline RealType quantile(const geometric_distribution<RealType, Policy>& dist, const RealType& x)
cannam@160 408 { // Quantile, percentile/100 or Percent Point geometric function.
cannam@160 409 // Return the number of expected failures k for a given probability p.
cannam@160 410
cannam@160 411 // Inverse cumulative Distribution Function or Quantile (percentile / 100) of geometric Probability.
cannam@160 412 // k argument may be integral, signed, or unsigned, or floating point.
cannam@160 413
cannam@160 414 static const char* function = "boost::math::quantile(const geometric_distribution<%1%>&, %1%)";
cannam@160 415 BOOST_MATH_STD_USING // ADL of std functions.
cannam@160 416
cannam@160 417 RealType success_fraction = dist.success_fraction();
cannam@160 418 // Check dist and x.
cannam@160 419 RealType result = 0;
cannam@160 420 if(false == geometric_detail::check_dist_and_prob
cannam@160 421 (function, success_fraction, x, &result, Policy()))
cannam@160 422 {
cannam@160 423 return result;
cannam@160 424 }
cannam@160 425
cannam@160 426 // Special cases.
cannam@160 427 if (x == 1)
cannam@160 428 { // Would need +infinity failures for total confidence.
cannam@160 429 result = policies::raise_overflow_error<RealType>(
cannam@160 430 function,
cannam@160 431 "Probability argument is 1, which implies infinite failures !", Policy());
cannam@160 432 return result;
cannam@160 433 // usually means return +std::numeric_limits<RealType>::infinity();
cannam@160 434 // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
cannam@160 435 }
cannam@160 436 if (x == 0)
cannam@160 437 { // No failures are expected if P = 0.
cannam@160 438 return 0; // Total trials will be just dist.successes.
cannam@160 439 }
cannam@160 440 // if (P <= pow(dist.success_fraction(), 1))
cannam@160 441 if (x <= success_fraction)
cannam@160 442 { // p <= pdf(dist, 0) == cdf(dist, 0)
cannam@160 443 return 0;
cannam@160 444 }
cannam@160 445 if (x == 1)
cannam@160 446 {
cannam@160 447 return 0;
cannam@160 448 }
cannam@160 449
cannam@160 450 // log(1-x) /log(1-success_fraction) -1; but use log1p in case success_fraction is small
cannam@160 451 result = boost::math::log1p(-x, Policy()) / boost::math::log1p(-success_fraction, Policy()) - 1;
cannam@160 452 // Subtract a few epsilons here too?
cannam@160 453 // to make sure it doesn't slip over, so ceil would be one too many.
cannam@160 454 return result;
cannam@160 455 } // RealType quantile(const geometric_distribution dist, p)
cannam@160 456
cannam@160 457 template <class RealType, class Policy>
cannam@160 458 inline RealType quantile(const complemented2_type<geometric_distribution<RealType, Policy>, RealType>& c)
cannam@160 459 { // Quantile or Percent Point Binomial function.
cannam@160 460 // Return the number of expected failures k for a given
cannam@160 461 // complement of the probability Q = 1 - P.
cannam@160 462 static const char* function = "boost::math::quantile(const geometric_distribution<%1%>&, %1%)";
cannam@160 463 BOOST_MATH_STD_USING
cannam@160 464 // Error checks:
cannam@160 465 RealType x = c.param;
cannam@160 466 const geometric_distribution<RealType, Policy>& dist = c.dist;
cannam@160 467 RealType success_fraction = dist.success_fraction();
cannam@160 468 RealType result = 0;
cannam@160 469 if(false == geometric_detail::check_dist_and_prob(
cannam@160 470 function,
cannam@160 471 success_fraction,
cannam@160 472 x,
cannam@160 473 &result, Policy()))
cannam@160 474 {
cannam@160 475 return result;
cannam@160 476 }
cannam@160 477
cannam@160 478 // Special cases:
cannam@160 479 if(x == 1)
cannam@160 480 { // There may actually be no answer to this question,
cannam@160 481 // since the probability of zero failures may be non-zero,
cannam@160 482 return 0; // but zero is the best we can do:
cannam@160 483 }
cannam@160 484 if (-x <= boost::math::powm1(dist.success_fraction(), dist.successes(), Policy()))
cannam@160 485 { // q <= cdf(complement(dist, 0)) == pdf(dist, 0)
cannam@160 486 return 0; //
cannam@160 487 }
cannam@160 488 if(x == 0)
cannam@160 489 { // Probability 1 - Q == 1 so infinite failures to achieve certainty.
cannam@160 490 // Would need +infinity failures for total confidence.
cannam@160 491 result = policies::raise_overflow_error<RealType>(
cannam@160 492 function,
cannam@160 493 "Probability argument complement is 0, which implies infinite failures !", Policy());
cannam@160 494 return result;
cannam@160 495 // usually means return +std::numeric_limits<RealType>::infinity();
cannam@160 496 // unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
cannam@160 497 }
cannam@160 498 // log(x) /log(1-success_fraction) -1; but use log1p in case success_fraction is small
cannam@160 499 result = log(x) / boost::math::log1p(-success_fraction, Policy()) - 1;
cannam@160 500 return result;
cannam@160 501
cannam@160 502 } // quantile complement
cannam@160 503
cannam@160 504 } // namespace math
cannam@160 505 } // namespace boost
cannam@160 506
cannam@160 507 // This include must be at the end, *after* the accessors
cannam@160 508 // for this distribution have been defined, in order to
cannam@160 509 // keep compilers that support two-phase lookup happy.
cannam@160 510 #include <boost/math/distributions/detail/derived_accessors.hpp>
cannam@160 511
cannam@160 512 #if defined (BOOST_MSVC)
cannam@160 513 # pragma warning(pop)
cannam@160 514 #endif
cannam@160 515
cannam@160 516 #endif // BOOST_MATH_SPECIAL_GEOMETRIC_HPP