pub fn wilson_interval(
successes: u64,
trials: u64,
level: ConfidenceLevel,
) -> (f64, f64)Expand description
Wilson score interval for a Bernoulli proportion at fixed n.
n == 0 returns (0.0, 1.0) – total ignorance, not an error: with zero trials nothing is
known about the proportion beyond it lying in [0, 1], so the widest possible interval is
the honest answer rather than a divide-by-zero or a panic.
successes above trials is not a domain error either: it saturates at trials (p = 1.0), so the call reports exactly the interval a fully-successful run of that size would.
This is deliberate, not merely tolerated: for p only just above 1.0 the radicand below
does not reliably go negative (z^2/(4n^2) can outweigh a small negative p(1-p)/n), so an
unclamped implementation would silently return a plausible-looking wrong interval rather
than a loud NaN – saturating p at the input removes that failure mode entirely instead
of documenting around it.
Unlike the naive Wald interval (p +- z * sqrt(p(1-p)/n)), the Wilson interval stays
inside [0, 1] and has correct coverage even at small n or p near 0 or 1 –
exactly the regime a hit-probability Monte Carlo run starts in before enough trials have
accumulated. Computed directly in “center +- spread” form (Wilson 1927; worked example in
Newcombe 1998, cross-checked by this module’s tests):
center = (p + z^2 / (2n)) / (1 + z^2 / n)
spread = (z / (1 + z^2 / n)) * sqrt(p(1-p)/n + z^2/(4n^2))where p = min(successes / trials, 1.0) and z is ConfidenceLevel::z. The result is
additionally clamped to [0, 1]: floating-point rounding in center +- spread can overshoot
by up to a few ULP right at the p == 0 / p == 1 edges, and a probability bound outside
[0, 1] is a worse answer than one that is merely maximally uninformative.