...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
If a statistical distribution is discrete then the
random variable can only have integer values - this leaves us with a problem
when calculating quantiles - we can either ignore the discreteness of the
distribution and return a real value, or we can round to an integer. As
it happens, computing integer values can be substantially faster than calculating
a real value, so there are definite advantages to returning an integer,
but we do then need to decide how best to round the result. The discrete_quantile
policy defines how
discrete quantiles work, and how integer results are rounded:
enum discrete_quantile_policy_type { real, integer_round_outwards, // default integer_round_inwards, integer_round_down, integer_round_up, integer_round_nearest }; template <discrete_quantile_policy_type> struct discrete_quantile;
The values that discrete_quantile
can take have the following meanings:
Ignores the discreteness of the distribution, and returns a real-valued result. For example:
#include <boost/math/distributions/negative_binomial.hpp> using namespace boost::math; using namespace boost::math::policies; typedef negative_binomial_distribution< double, policy<discrete_quantile<integer_round_inwards> > > dist_type; // Lower quantile: double x = quantile(dist_type(20, 0.3), 0.05); // Upper quantile: double y = quantile(complement(dist_type(20, 0.3), 0.05));
Results in x =
27.3898
and y
= 68.1584
.
This is the default policy: an integer value is returned so that:
This is normally the safest rounding policy, since it ensures that both one and two sided intervals are guaranteed to have at least the requested coverage. For example:
#include <boost/math/distributions/negative_binomial.hpp> using namespace boost::math; // Lower quantile rounded down: double x = quantile(negative_binomial(20, 0.3), 0.05); // Upper quantile rounded up: double y = quantile(complement(negative_binomial(20, 0.3), 0.05));
Results in x =
27
(rounded down from 27.3898) and
y =
69
(rounded up from 68.1584).
The variables x and y are now defined so that:
cdf(negative_binomial(20), x) <= 0.05 cdf(negative_binomial(20), y) >= 0.95
In other words we guarantee at least 90% coverage in the central region overall, and also no more than 5% coverage in each tail.
This is the opposite of integer_round_outwards: an integer value is returned so that:
For example:
#include <boost/math/distributions/negative_binomial.hpp> using namespace boost::math; using namespace boost::math::policies; typedef negative_binomial_distribution< double, policy<discrete_quantile<integer_round_inwards> > > dist_type; // Lower quantile rounded up: double x = quantile(dist_type(20, 0.3), 0.05); // Upper quantile rounded down: double y = quantile(complement(dist_type(20, 0.3), 0.05));
Results in x =
28
(rounded up from 27.3898) and
y =
68
(rounded down from 68.1584).
The variables x and y are now defined so that:
cdf(negative_binomial(20), x) >= 0.05 cdf(negative_binomial(20), y) <= 0.95
In other words we guarantee at no more than 90% coverage in the central region overall, and also at least 5% coverage in each tail.
Always rounds down to an integer value, no matter whether it's an upper or a lower quantile.
Always rounds up to an integer value, no matter whether it's an upper or a lower quantile.
Always rounds to the nearest integer value, no matter whether it's an upper or a lower quantile. This will produce the requested coverage in the average case, but for any specific example may results in either significantly more or less coverage than the requested amount. For example:
For example:
#include <boost/math/distributions/negative_binomial.hpp> using namespace boost::math; using namespace boost::math::policies; typedef negative_binomial_distribution< double, policy<discrete_quantile<integer_round_nearest> > > dist_type; // Lower quantile rounded up: double x = quantile(dist_type(20, 0.3), 0.05); // Upper quantile rounded down: double y = quantile(complement(dist_type(20, 0.3), 0.05));
Results in x =
27
(rounded from 27.3898) and y = 68
(rounded from 68.1584).