FA-321 / Floating-point arithmetic / Open access
Large cancelling terms erase a small summand · case 01
A mathematically nonzero residual disappears when large positive and negative terms cancel.
ROOT CAUSE
Sequential floating-point accumulation rounds away a small term before the compensating large term arrives.
VERIFIED REPAIR
Use an accurate summation routine that retains multiple partial sums across magnitude changes.
Unsuccessful approach: A single Kahan compensation term is still lost for some severe cancellation orderings; compensation is not a universal accuracy guarantee.
Case contract
Sum a finite sequence of finite binary floating-point values using math.fsum semantics. These bounded fixtures have exactly representable expected residuals and do not overflow the final result.
Why this case matters
Mixed-sign measurements with a large dynamic range can expose weaknesses that positive-only sums do not. The experiment compares ordinary accumulation, Kahan accumulation, and standard-library accurate summation.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(values):
total = 0.0
for value in values:
total += value
return total
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
large = float(2 ** 54)
residual = N + 0.125
check('small residual between cancelling large terms', solve([large, residual, -large]), residual)
check('negative residual between cancelling large terms', solve([-large, -residual, large]), -residual)
check('small terms before cancellation', solve([0.25] * N + [large, -large]), N / 4)
check('ordinary exact binary fractions', solve([0.125, 0.25, 0.5] * N), 0.875 * N)
check('opposite terms cancel exactly', solve([large, -large] * N), 0.0)
check('one finite observation', solve([residual]), residual)
check('empty sum', solve([]), 0.0)
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 |
|---|---|---|---|
| small residual between cancelling large terms | 0.0 | 1.125 | Failed |
| negative residual between cancelling large terms | 0.0 | -1.125 | Failed |
| small terms before cancellation | 0.0 | 0.25 | Failed |
| ordinary exact binary fractions | 0.875 | 0.875 | Passed |
| opposite terms cancel exactly | 0.0 | 0.0 | Passed |
| one finite observation | 1.125 | 1.125 | Passed |
| empty sum | 0.0 | 0.0 | Passed |
SHA-256 / 6dd777c539e82241d7c7d692a318b4b701bc9cbecc2057e2a9c96f8a52dfd558
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(values):
total, correction = 0.0, 0.0
for value in values:
adjusted = value - correction
updated = total + adjusted
correction = (updated - total) - adjusted
total = updated
return total
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
large = float(2 ** 54)
residual = N + 0.125
check('small residual between cancelling large terms', solve([large, residual, -large]), residual)
check('negative residual between cancelling large terms', solve([-large, -residual, large]), -residual)
check('small terms before cancellation', solve([0.25] * N + [large, -large]), N / 4)
check('ordinary exact binary fractions', solve([0.125, 0.25, 0.5] * N), 0.875 * N)
check('opposite terms cancel exactly', solve([large, -large] * N), 0.0)
check('one finite observation', solve([residual]), residual)
check('empty sum', solve([]), 0.0)
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 |
|---|---|---|---|
| small residual between cancelling large terms | 2.0 | 1.125 | Failed |
| negative residual between cancelling large terms | -2.0 | -1.125 | Failed |
| small terms before cancellation | 0.0 | 0.25 | Failed |
| ordinary exact binary fractions | 0.875 | 0.875 | Passed |
| opposite terms cancel exactly | 0.0 | 0.0 | Passed |
| one finite observation | 1.125 | 1.125 | Passed |
| empty sum | 0.0 | 0.0 | Passed |
SHA-256 / 237bcce6055006b6423aca9fdce9c3cf4e0565f4538393cb06d0db09458db130
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(values):
return math.fsum(values)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
large = float(2 ** 54)
residual = N + 0.125
check('small residual between cancelling large terms', solve([large, residual, -large]), residual)
check('negative residual between cancelling large terms', solve([-large, -residual, large]), -residual)
check('small terms before cancellation', solve([0.25] * N + [large, -large]), N / 4)
check('ordinary exact binary fractions', solve([0.125, 0.25, 0.5] * N), 0.875 * N)
check('opposite terms cancel exactly', solve([large, -large] * N), 0.0)
check('one finite observation', solve([residual]), residual)
check('empty sum', solve([]), 0.0)
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 |
|---|---|---|---|
| small residual between cancelling large terms | 1.125 | 1.125 | Passed |
| negative residual between cancelling large terms | -1.125 | -1.125 | Passed |
| small terms before cancellation | 0.25 | 0.25 | Passed |
| ordinary exact binary fractions | 0.875 | 0.875 | Passed |
| opposite terms cancel exactly | 0.0 | 0.0 | Passed |
| one finite observation | 1.125 | 1.125 | Passed |
| empty sum | 0.0 | 0.0 | Passed |
SHA-256 / 324c2ff074f9def0f207d84c6897d4d1be72bcbea9565a7972037479efddbbe9
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.068094+00:00.
Case digest / 4d4e34d217ad2be9bb4ba43caf527c3724b48c9ce168b549e5786068e9dff41e