FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 9 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
unordered even-sample median13/2Failed
quarter percentile interpolates03/4Failed
zeroth percentile is minimum00Passed
hundredth percentile is maximum33Passed
duplicate observations stay weighted by count01/2Failed
negative values interpolate-1-1/2Failed
single observation11Passed
invalid percentile rejectedNoneNonePassed
empty sampleNoneNonePassed

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 fixtureActualExpectedOutcome
unordered even-sample median1/23/2Failed
quarter percentile interpolates3/43/4Passed
zeroth percentile is minimum30Failed
hundredth percentile is maximum23Failed
duplicate observations stay weighted by count1/21/2Passed
negative values interpolate-1/2-1/2Passed
single observation11Passed
invalid percentile rejectedNoneNonePassed
empty sampleNoneNonePassed

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 fixtureActualExpectedOutcome
unordered even-sample median3/23/2Passed
quarter percentile interpolates3/43/4Passed
zeroth percentile is minimum00Passed
hundredth percentile is maximum33Passed
duplicate observations stay weighted by count1/21/2Passed
negative values interpolate-1/2-1/2Passed
single observation11Passed
invalid percentile rejectedNoneNonePassed
empty sampleNoneNonePassed

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