GCC -ffast-math and IEEE-754 Semantics
-ffast-math changes floating-point assumptions around reassociation, NaN, infinity and signed zero; it is a numerical contract, not only a speed flag.
An algebraically valid transformation is not automatically equivalent under IEEE-754 floating point.
(a+b)+cand
a+(b+c)can differ because intermediate values are rounded. NaN, infinity and signed zero create additional observable behavior.
I therefore treat -ffast-math as a numerical-semantics decision, not simply a performance switch.
It enables a group of assumptions
GCC uses -ffast-math to enable several optimization assumptions. The exact set is version-dependent, so I verify the compiler documentation used for the build.
Reassociation changes results
Allowing reassociation can expose better vectorization but changes operation order. Whether the difference is acceptable depends on the application's error budget.
NaN can be part of logic
Code may intentionally test isnan() or handle infinity. An optimization mode that assumes those values do not occur can invalidate such control flow.
Signed zero is observable
+0.0 and -0.0 compare equal but can produce different reciprocal infinities. Code that relies on this distinction needs strict semantics.
FMA may differ bit-for-bit
Fused multiply-add rounds once instead of rounding multiplication and addition separately. A different bit pattern is not necessarily less accurate; reproducibility requirements determine whether it is acceptable.
SIMD makes relaxed semantics attractive
Relaxed rules can permit transformations useful for SIMD. The speedup is valuable only if numerical deviation remains within a defined tolerance.
Determinism needs extra care
Compiler version, ISA and FMA availability can change evaluation. In reproducible systems I record compiler flags and numerical tolerances as release inputs.
How I test
I compare a reference build and optimized build on ordinary values, cancellation cases, extreme magnitudes, signed zeros and NaN/infinity where meaningful. I measure both speed and numerical deviation.
Avoid blind global -Ofast
When the hot path is local, a narrow compilation scope is easier to validate than changing floating-point semantics across the entire application.
The engineering sequence is:
measure
→ identify bottleneck
→ relax semantics deliberately
→ measure performance
→ measure numerical errorReferences
- GCC Optimization Options
- IEEE Std 754-2019