Summary
Budget-window impact fields are typed float and summed with += across up to 75 years. At trillion-dollar magnitudes this accumulates meaningful precision loss — the totals and the per-year impacts in the response will not be self-consistent to the cent (or even to the dollar).
Location
projects/policyengine-api-simulation/src/modal/budget_window_results.py:54-72
projects/policyengine-api-simulation/src/modal/gateway/models.py:113-128
What goes wrong
class BudgetWindowAnnualImpact(BaseModel):
year: str
taxRevenueImpact: float
federalTaxRevenueImpact: float
...
def sum_annual_impacts(annual_impacts):
totals = {"taxRevenueImpact": 0, ...}
for annual_impact in annual_impacts:
totals["taxRevenueImpact"] += annual_impact.taxRevenueImpact
...
return BudgetWindowTotals(**totals)
Federal revenue impacts in the trillions sum over 75 years exceed 2^53 and quickly lose integer precision in IEEE-754 double. Even at sub-trillion magnitudes, the naive += accumulation introduces drift that makes the reported totals.budgetaryImpact disagree with sum(annualImpacts.budgetaryImpact) when clients re-check.
Suggested fix
- Model impacts as
decimal.Decimal or integer cents at the boundary; convert to float only for display.
- Or use
math.fsum(...) in sum_annual_impacts to reduce accumulation error.
- Add a test that sums 75 years of trillion-dollar impacts and asserts totals equal the exact sum.
Severity
Medium. Silent numerical drift in public-facing budget numbers.
Summary
Budget-window impact fields are typed
floatand summed with+=across up to 75 years. At trillion-dollar magnitudes this accumulates meaningful precision loss — the totals and the per-year impacts in the response will not be self-consistent to the cent (or even to the dollar).Location
projects/policyengine-api-simulation/src/modal/budget_window_results.py:54-72projects/policyengine-api-simulation/src/modal/gateway/models.py:113-128What goes wrong
Federal revenue impacts in the trillions sum over 75 years exceed 2^53 and quickly lose integer precision in IEEE-754 double. Even at sub-trillion magnitudes, the naive
+=accumulation introduces drift that makes the reportedtotals.budgetaryImpactdisagree withsum(annualImpacts.budgetaryImpact)when clients re-check.Suggested fix
decimal.Decimalor integer cents at the boundary; convert tofloatonly for display.math.fsum(...)insum_annual_impactsto reduce accumulation error.Severity
Medium. Silent numerical drift in public-facing budget numbers.