Use when you must test an observed count against a hypothesized proportion: compute the exact binomial tail probability of k or fewer successes in n trials under a null proportion p zero, form the two-sided p-value by doubling the one-sided tail mass capped at one with an optional mid-p variant and a continuity-corrected normal cross-check, and decide the verdict against a significance level. Produces the exact p-value, the lower and upper tail masses, the observed direction, and the small-co...
Installs into .claude/skills of the current project.
Are you the author of Exact Binomial Test?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/ashfordeou-exact-binomial-test)
---
name: exact-binomial-test
description: "Use when you must test an observed count against a hypothesized proportion: compute the exact binomial tail probability of k or fewer successes in n trials under a null proportion p zero, form the two-sided p-value by doubling the one-sided tail mass capped at one with an optional mid-p variant and a continuity-corrected normal cross-check, and decide the verdict against a significance level. Produces the exact p-value, the lower and upper tail masses, the observed direction, and the small-count recommendation that gate attribute-data significance claims. Trigger: exact binomial test, binomial tail probability, k of n successes, single proportion significance, mid p correction, attribute data significance."
license: Apache-2.0
compliance: STANDARDS-REF
standards:
- id: naca-tr-824
reference-only: true
gated: false
domain: cross-cutting
pack: numerics
compatibility: "agentskills.io SKILL.md; any SKILL.md host (Claude Code, Hermes, OpenClaw)"
metadata:
domain: cross-cutting
subdomain: numerics
tags: [exact-binomial-test, single-proportion-test, binomial-tail-p-value, k-of-n-significance, mid-p-binomial]
version: 0.1.0
author: AeroSkills
---
# Exact Binomial Test (cross-cutting/numerics/exact-binomial-test)
Use when the task is a significance test of an observed count against a
hypothesized proportion: does k successes in n trials support a null pass
rate or defect rate p zero? This leaf computes the exact binomial tail
P(X <= k) under the null, forms the one-sided and two-sided p-values with
the documented doubling convention (capped at one) plus the optional mid-p
variant, cross-checks with the normal approximation carrying the
continuity correction, and returns the small-count recommendation that
gates attribute-data significance claims. It is pure Python, stdlib only
(math.comb, math.erfc), deterministic, with no RNG. It pairs with the
sibling numerics leaves: interval estimation of the same proportion is
cross-cutting/numerics/proportion-confidence-interval, parametric verdicts
on continuous samples are cross-cutting/numerics/hypothesis-testing, and
two-sample table tests are cross-cutting/numerics/fisher-exact-test.
## Domain quick reference
- Single-outcome mass: P(X = k) = C(n, k) * p0^k * (1 - p0)^(n - k),
computed with math.comb (binomial_probability).
- Lower tail: P(X <= k) = sum over j = 0..k of C(n, j) * p0^j *
(1 - p0)^(n - j) (binomial_cdf), exactly 1.0 when k equals n.
- Observed direction: "less" when k sits at or below the null mean n*p0,
"greater" otherwise.
- One-sided p-value: the lower tail for the less alternative, the upper
tail P(X >= k) = 1 - P(X <= k - 1) for the greater alternative.
- Two-sided p-value: the observed-direction one-sided mass doubled and
capped at 1, the doubling convention shared with the nonparametric
two-sided family; any one-sided mass at or above one half therefore
reports exactly 1.0.
- Mid-p variant: p_mid = p_two_sided - P(X = k) for the two-sided case,
and the one-sided p minus half of P(X = k) for a one-sided case, the
standard relaxation of the conservative doubling (assumption recorded
here; the module applies it only when midp is True).
- Normal cross-check: mean n*p0, standard deviation sqrt(n*p0*(1 - p0)),
continuity correction moving the count half a step toward the null mean
(k + 0.5 below the mean, k - 0.5 above), z = (k_c - mean) / sd, and the
two-sided normal p = 2 * (1 - Phi(|z|)) from math.erfc.
- Small-count rule: min_expected = n * min(p0, 1 - p0); below 5 the
verdict is exact-test-recommended, otherwise
normal-approximation-adequate.
- Identities: p0 = 0.5 with k = n/2 is the most central count and gives a
two-sided p of exactly 1.0; the CDF at k = n is 1.0; the masses sum to 1
over k; the normal approximation approaches the exact p as n grows.
## Workflow
1. Fix the inputs: observed successes k, trial count n, hypothesized null
proportion p0, the alternative (two-sided, less or greater) and the
significance level alpha (0.05 by default).
2. Tail-mass traverse: binomial_probability returns the single-outcome
mass P(X = k) and binomial_cdf returns the cumulative lower tail
P(X <= k).
3. Exact-test traverse: binomial_exact_test(k, n, p0, alternative)
returns the verdict dict with the exact keys p_lower_tail, p_upper_tail,
p_value, direction and midp_applied, the two-sided p_value doubling the
observed-direction one-sided mass and capping at 1.
4. Mid-p traverse: rerun binomial_exact_test with midp True to relax the
conservative doubling by the probability of the observed count.
5. Normal cross-check traverse: binomial_normal_approximation(k, n, p0)
returns the dict with z (continuity correction toward the null mean)
and the two-sided normal p_value for large samples.
6. Small-count traverse: small_count_recommendation(n, p0) returns
min_expected and the verdict that gates the exact tail against the
approximation for attribute data.
7. Verdict bookkeeping: compare the p_value against alpha and record
reject or fail-to-reject at the chosen significance level.
8. Verification run: confirm the anchors and guards with the contract
test, python3 scripts/test_exact_binomial_test.py (35 tests,
deterministic, offline).
## Worked example
n = 40, k = 8, p0 = 0.30. Module outputs (contract test anchors in
parentheses):
- Lower tail: binomial_cdf(8, 40, 0.3) = 0.11100917524979735 (within 1e-3
of 0.1110).
- Exact test: p_lower_tail 0.11100917524979735, p_upper_tail
0.9447171128462573, p_value 0.2220183504995947 (within 2e-3 of 0.2220),
direction less, fail-to-reject at the 0.05 significance level; the
two-sided p is exactly twice the 0.1110 lower tail, uncapped.
- Mid-p variant: 0.1662920624035401, the doubled 0.2220 minus the observed
mass P(X = 8) = 0.0557262880960546.
- Normal cross-check: mean 12, sd sqrt(8.4) = 2.898275, z =
(8 - 12 + 0.5) / 2.898275 = -1.20761472884912 (within 0.01 of -1.208),
two-sided p 0.22719549110006437 (within 0.005 of 0.227).
- n = 20, k = 2, p0 = 0.30: binomial_cdf(2, 20, 0.3) =
0.03548313229846864 (within 1e-3 of 0.0355) and the less alternative
p_value rejects at 0.05.
- Upper-side example: n = 40, k = 16 sits above the null mean 12, so the
direction is greater, the upper tail is 0.11514665058139029 and the
doubled two-sided p_value is 0.23029330116278057.
- Small count: n = 20, p0 = 0.30 gives min_expected 6.0 and
normal-approximation-adequate; n = 10, p0 = 0.05 gives min_expected 0.5
and exact-test-recommended.
## Verification
- Confirm binomial_cdf(8, 40, 0.3) returns 0.11100917524979735 and
binomial_exact_test(8, 40, 0.3) returns p_value 0.2220183504995947 with
direction less, failing to reject at 0.05.
- Confirm binomial_exact_test(2, 20, 0.3, alternative="less") rejects at
0.05 with p_value 0.03548313229846864.
- Confirm binomial_normal_approximation(8, 40, 0.3) returns z
-1.20761472884912 and p_value 0.22719549110006437.
- Confirm the most central count p0 = 0.5, n = 10, k = 5 gives a two-sided
p_value of exactly 1.0, and the mid-p variant 0.75390625.
- Confirm binomial_cdf(k = n) returns exactly 1.0 and the
binomial_probability masses sum to 1 over k.
- Confirm small_count_recommendation(20, 0.3) returns min_expected 6.0
with the adequate verdict and small_count_recommendation(10, 0.05)
returns 0.5 with exact-test-recommended.
- Confirm the normal approximation error at n = 400 is below half the
error at n = 40 for the same count share (convergence with n).
- Confirm every non-physical input raises ValueError: k 41 with n 40, k
-1, k 2.5, n 0, a fractional n, p0 or p exactly 0 or 1, p outside
(0, 1), and an alternative outside two-sided, less and greater.
- Run the contract test offline: python3 scripts/test_exact_binomial_test.py
(35 tests, deterministic).
## Related leaves
- cross-cutting/numerics/hypothesis-testing: the verdict workflow for
continuous-sample comparisons without an exact count tail.
- cross-cutting/numerics/proportion-confidence-interval: interval
estimation for a proportion, the estimation counterpart of this test.
- cross-cutting/numerics/rank-based-hypothesis-testing: nonparametric
alternatives that rank the observations instead of counting successes.
- cross-cutting/numerics/fisher-exact-test: exact tests on contingency
tables built from two samples, with no single-count null-proportion
input.
## Pitfalls
- Running the normal approximation on small expected counts: when
min_expected falls below 5 the exact tail is required; run the
small-count traverse first and honor the exact-test-recommended verdict
for attribute data.
- Forgetting the doubling cap: doubling a one-sided mass at or above one
half caps at 1.0, so the most central count, p0 = 0.5 with k = n/2,
reports a two-sided p_value of exactly 1.0, not 1.25.
- Reporting a mid-p value without its flag: the mid-p variant subtracts
the observed mass from the doubled two-sided p (and half of it from a
one-sided p), so it is always below the conservative value and the
midp_applied key must be reported with it.
- Confusing the direction with the alternative: direction records where k
sits relative to the null mean n*p0 (less at or below, greater above),
while the alternative parameter chooses which tail forms the one-sided
p-value; a count above the mean still gives a large less p-value.
- Pointing the continuity correction the wrong way: the half step moves
toward the null mean, so z uses k + 0.5 below the mean and k - 0.5
above it.
- Feeding boundary proportions: p0 exactly 0 or 1 is non-physical for a
test of the open interval (0, 1) and raises ValueError, and the observed
count must be an integer inside [0, n].
- Forgetting the edge counts: k = 0 gives an upper tail of exactly 1.0 and
k = n gives a lower tail of exactly 1.0; both are valid test inputs, not
errors.
## Behavior contract (gate 3)
Run the deterministic contract test (stdlib unittest, offline):
python3 scripts/test_exact_binomial_test.py
The test covers the worked-example anchors (lower tail 0.1110 and two-sided
p 0.2220 for eight successes in forty trials against p zero 0.30, 0.0355
for two in twenty, z -1.208 with p 0.227), the doubling and cap identities
at the most central count, the direction semantics for counts above the
null mean, the mid-p identities for the two-sided and one-sided variants,
the continuity-correction z formula on both sides of the mean, the
large-sample convergence of the normal approximation, the small-count
verdicts at and around the 5 boundary, the distribution identities (CDF at
k = n exactly 1, masses summing to 1, edge counts k = 0 and k = n, single
trial), the exact dict keys and determinism, and every ValueError guard
from the validation list.
## Compliance
- Standards referenced, not reproduced: NACA-TR-824 frames the statistical
methodology context; the exact binomial tail relations above are standard
engineering methodology, summary-only per standards-map.yaml.
- compliance: STANDARDS-REF, gated: false.