FP32 per-op error bounds #
Proofs about numerical code should not have to expand the definition of “float32 rounding” every
time they use + or exp. This file provides reusable rewrite theorems for FP32
rounding-error reasoning.
We collect those lemmas for TorchLean’s FP32 model:
- each primitive op is interpreted as “compute in
ℝ, then round to the binary32 grid”, and - the rounding step has a standard half-ULP absolute error bound.
This mirrors the standard mental model behind PyTorch/IEEE float analysis (even though our proof backend is not a bit-level model): it’s the classic “real computation + rounding error” split.
The pattern is always:
- compute the exact real result,
- apply the
FP32rounding operator, - bound the rounding error by
eps₃₂ x(half an ulp atx; seeNN/Floats/FP32/Notation.lean).
Important nuance: these are local statements about a single rounding step. Whole-network bounds typically combine these with:
- algebra/triangle-inequality steps, or
- higher-level composition lemmas in
NN/Proofs/RuntimeApprox/*.
References #
- IEEE Std 754-2019, "IEEE Standard for Floating-Point Arithmetic".
- D. Goldberg, "What Every Computer Scientist Should Know About Floating-Point Arithmetic", ACM Computing Surveys, 1991.
- N. J. Higham, "Accuracy and Stability of Numerical Algorithms", SIAM, 2nd ed., 2002.
This module works with a proof-friendly float32 semantics ("real operation + one rounding step"). Relating this abstraction to specific hardware/libm behavior is a separate, target-specific trust boundary handled elsewhere in TorchLean.
Per-op rounding error lemmas #
Core rounding lemma for the binary32 parameters fixed by FP32.
This is the “one thing we use everywhere”: once you know an operation is defined as “round the real result”, the proof goal reduces to an instance of this lemma.
Informal: if fl32(x) denotes rounding x : ℝ to the binary32 grid, then
|fl32(x) - x| ≤ eps₃₂(x).
Division: one real division followed by one rounding step.
This does not say division is “well-conditioned”; it only isolates the rounding stage.
Informal: |fl32(a/b) - (a/b)| ≤ eps₃₂(a/b).
Transcendentals (proof semantics) #
In FP32, transcendental functions are specified as: apply the real function, then round.
That is not how hardware/libm is implemented, but it is exactly the right abstraction for proofs: it gives a clear mathematical meaning and a one-rounding-step error theorem.
Informal: |fl32(exp(x)) - exp(x)| ≤ eps₃₂(exp(x)), and similarly for the other functions below.
log in the proof model: real log followed by rounding.
Domain note: the inequality is about rounding error around Real.log a.val; it does not assert
anything about a.val > 0.
Informal: |fl32(log(x)) - log(x)| ≤ eps₃₂(log(x)).
abs in the proof model: real absolute value followed by rounding.
Even though |x| is exact over ℝ, we still round the result because this is a “round after every
primitive” semantics.
Informal: |fl32(|x|) - |x|| ≤ eps₃₂(|x|).