FA-336 / Statistics / Open access
Percentile interpolation uses unsorted observation positions · case 01
A percentile depends on input order or jumps to a nearest-rank value instead of the specified interpolated value.
ROOT CAUSE
The implementation changes the percentile definition or interpolates before sorting the sample.
VERIFIED REPAIR
Sort the observations and linearly interpolate at rank (n-1)*p/100 using exact rational arithmetic.
Unsuccessful approach: Adding interpolation while assuming input was already sorted leaves valid unordered samples with incorrect quantiles.
Case contract
For an integer sample and integer percentile p from 0 through 100, return the reduced Fraction string for linear interpolation at h=(n-1)*p/100 in sorted order. Empty samples and out-of-range p return None.
Why this case matters
Percentile definitions differ across libraries. This case specifies one convention and tests order independence instead of treating all percentile algorithms as interchangeable.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(values, percent):
if not values or not 0 <= percent <= 100:
return None
ordered = sorted(values)
index = max(0, math.ceil(len(values) * percent / 100) - 1)
return str(ordered[index])
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
values = [3 * N, 0, N, 2 * N]
check('unordered even-sample median', solve(values, 50), str(Fraction(3 * N, 2)))
check('quarter percentile interpolates', solve([0, N, 2 * N, 3 * N], 25), str(Fraction(3 * N, 4)))
check('zeroth percentile is minimum', solve(values, 0), '0')
check('hundredth percentile is maximum', solve(values, 100), str(3 * N))
check('duplicate observations stay weighted by count', solve([0, 0, N, N], 50), str(Fraction(N, 2)))
check('negative values interpolate', solve([-N, 0, N], 25), str(Fraction(-N, 2)))
check('single observation', solve([N], 73), str(N))
check('invalid percentile rejected', solve(values, 101), None)
check('empty sample', solve([], 50), None)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| unordered even-sample median | 1 | 3/2 | Failed |
| quarter percentile interpolates | 0 | 3/4 | Failed |
| zeroth percentile is minimum | 0 | 0 | Passed |
| hundredth percentile is maximum | 3 | 3 | Passed |
| duplicate observations stay weighted by count | 0 | 1/2 | Failed |
| negative values interpolate | -1 | -1/2 | Failed |
| single observation | 1 | 1 | Passed |
| invalid percentile rejected | None | None | Passed |
| empty sample | None | None | Passed |
SHA-256 / 7d3abb93954fa551955be424f3cf6bc8d09ad2d2e654e2bbcd9ffb8cbcb6cf48
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(values, percent):
if not values or not 0 <= percent <= 100:
return None
rank = Fraction((len(values) - 1) * percent, 100)
index = rank.numerator // rank.denominator
upper = min(index + 1, len(values) - 1)
return str(Fraction(values[index]) + (rank - index) * (values[upper] - values[index]))
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
values = [3 * N, 0, N, 2 * N]
check('unordered even-sample median', solve(values, 50), str(Fraction(3 * N, 2)))
check('quarter percentile interpolates', solve([0, N, 2 * N, 3 * N], 25), str(Fraction(3 * N, 4)))
check('zeroth percentile is minimum', solve(values, 0), '0')
check('hundredth percentile is maximum', solve(values, 100), str(3 * N))
check('duplicate observations stay weighted by count', solve([0, 0, N, N], 50), str(Fraction(N, 2)))
check('negative values interpolate', solve([-N, 0, N], 25), str(Fraction(-N, 2)))
check('single observation', solve([N], 73), str(N))
check('invalid percentile rejected', solve(values, 101), None)
check('empty sample', solve([], 50), None)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| unordered even-sample median | 1/2 | 3/2 | Failed |
| quarter percentile interpolates | 3/4 | 3/4 | Passed |
| zeroth percentile is minimum | 3 | 0 | Failed |
| hundredth percentile is maximum | 2 | 3 | Failed |
| duplicate observations stay weighted by count | 1/2 | 1/2 | Passed |
| negative values interpolate | -1/2 | -1/2 | Passed |
| single observation | 1 | 1 | Passed |
| invalid percentile rejected | None | None | Passed |
| empty sample | None | None | Passed |
SHA-256 / eefc5f1324fcd4ef9d472f024605c0fe86a0b24c8bc321c29b1c6d0c88657876
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
from fractions import Fraction
import math
N = 1
observations = []
def solve(values, percent):
if not values or not 0 <= percent <= 100:
return None
ordered = sorted(values)
rank = Fraction((len(ordered) - 1) * percent, 100)
index = rank.numerator // rank.denominator
upper = min(index + 1, len(ordered) - 1)
return str(Fraction(ordered[index]) + (rank - index) * (ordered[upper] - ordered[index]))
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
values = [3 * N, 0, N, 2 * N]
check('unordered even-sample median', solve(values, 50), str(Fraction(3 * N, 2)))
check('quarter percentile interpolates', solve([0, N, 2 * N, 3 * N], 25), str(Fraction(3 * N, 4)))
check('zeroth percentile is minimum', solve(values, 0), '0')
check('hundredth percentile is maximum', solve(values, 100), str(3 * N))
check('duplicate observations stay weighted by count', solve([0, 0, N, N], 50), str(Fraction(N, 2)))
check('negative values interpolate', solve([-N, 0, N], 25), str(Fraction(-N, 2)))
check('single observation', solve([N], 73), str(N))
check('invalid percentile rejected', solve(values, 101), None)
check('empty sample', solve([], 50), None)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| unordered even-sample median | 3/2 | 3/2 | Passed |
| quarter percentile interpolates | 3/4 | 3/4 | Passed |
| zeroth percentile is minimum | 0 | 0 | Passed |
| hundredth percentile is maximum | 3 | 3 | Passed |
| duplicate observations stay weighted by count | 1/2 | 1/2 | Passed |
| negative values interpolate | -1/2 | -1/2 | Passed |
| single observation | 1 | 1 | Passed |
| invalid percentile rejected | None | None | Passed |
| empty sample | None | None | Passed |
SHA-256 / 64d853195212f7244c218e380022d14595e9b43979d0ba320dbb18c0a7c6ef0f
Verification & scope
This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:36:52.118149+00:00.
Case digest / 659948f51f1652c566c70bb3d6cd65c5f8a7d4fea06274b1d0c906461b062d9d