91double compute(Count_ drawn_inside, Count_ num_inside, Count_ num_outside,
const Count_ num_drawn,
const Options& options) {
94 if (drawn_inside <= 0 || (num_drawn >= num_outside && drawn_inside <= num_drawn - num_outside)) {
95 return (options.
log ? 0 : 1);
97 if (drawn_inside > num_drawn || drawn_inside > num_inside) {
98 return (options.
log ? -std::numeric_limits<double>::infinity() : 0);
101 if (drawn_inside < 0 || (num_drawn >= num_outside && drawn_inside < num_drawn - num_outside)) {
102 return (options.
log ? -std::numeric_limits<double>::infinity() : 0);
104 if (drawn_inside >= num_drawn || drawn_inside >= num_inside) {
105 return (options.
log ? 0 : 1);
109 if (std::numeric_limits<Count_>::max() - num_inside < num_outside) {
110 throw std::runtime_error(
"sum of 'num_inside' and 'num_outside' results in integer overflow");
112 const Count_ num_total = num_outside + num_inside;
125 if (
static_cast<double>(drawn_inside) *
static_cast<double>(num_total) >
static_cast<double>(num_drawn) *
static_cast<double>(num_inside)) {
126 std::swap(num_inside, num_outside);
127 drawn_inside = num_drawn - drawn_inside - 1;
128 needs_upper = !needs_upper;
142 Count_ denom1a = drawn_inside, denom1b = num_inside - denom1a;
143 Count_ denom2a = num_drawn - drawn_inside, denom2b = num_outside - denom2a;
144 const long double log_probability =
145 + internal::lfactorial(num_inside) - internal::lfactorial(denom1a) - internal::lfactorial(denom1b)
146 + internal::lfactorial(num_outside) - internal::lfactorial(denom2a) - internal::lfactorial(denom2b)
147 - internal::lfactorial(num_total) + internal::lfactorial(num_drawn) + internal::lfactorial(num_total - num_drawn);
149 long double cumulative = 0;
150 long double partial_probability = 1;
152 for (Count_ k = drawn_inside; k > 0; --k) {
156 long double mult = (
static_cast<long double>(denom1a) *
static_cast<long double>(denom2b)) / (
static_cast<long double>(denom1b) *
static_cast<long double>(denom2a));
157 partial_probability *= mult;
158 if (partial_probability == 0) {
161 cumulative += partial_probability;
167 const long double log_cumulative = std::log1p(cumulative) + log_probability;
170 return log_cumulative;
172 return std::exp(log_cumulative);
181 if (log_cumulative > -std::log(2)) {
182 const auto p = -std::expm1(log_cumulative);
183 return (p > 0 ? std::log(p) : -std::numeric_limits<double>::infinity());
185 const auto p = -std::exp(log_cumulative);
186 return (p > -1 ? std::log1p(p) : -std::numeric_limits<double>::infinity());
189 return -std::expm1(log_cumulative);
double compute(Count_ drawn_inside, Count_ num_inside, Count_ num_outside, const Count_ num_drawn, const Options &options)
Definition phyper.hpp:91