HN
Today

It's OK to compare floating-points for equality

This article challenges the long-held programming dogma that direct floating-point equality comparisons are always bad, arguing that epsilon-based comparisons often create more problems than they solve. It delves into numerous practical examples from geometry, physics, and linear algebra to demonstrate superior, more robust solutions. This contrarian yet well-reasoned stance resonates with HN's audience, who appreciate deep technical insights that challenge conventional wisdom.

6
Score
1
Comments
#5
Highest Rank
14h
on Front Page
First Seen
Apr 18, 10:00 AM
Last Seen
Apr 18, 11:00 PM
Rank Over Time
19657691117181621242728

The Lowdown

The article boldly asserts that it's often acceptable, and even preferable, to compare floating-point numbers for exact equality, directly contradicting the common advice to always use epsilon-based comparisons. The author, with over 15 years of experience in graphics and simulations, argues that epsilons are frequently a hacky, non-solution that leads to hard-to-debug issues and rarely addresses the root problem. Instead, a deeper understanding of floating-point arithmetic and careful algorithm design usually provides better and more robust solutions.

The author illustrates this point through several case studies:

  • Floating-points are not a black box: Floating-point numbers are deterministic and highly standardized, not random. Their inexactness doesn't imply uncertainty; single operations produce the closest representable value.
  • Problems with epsilons: Epsilon comparisons are hacky, cascade into hard-to-debug issues, and are often arbitrary guesses. They also break transitivity, which many algorithms rely on.
  • Grid-based movement: Instead of using an epsilon to check if a unit reached a target, separate the game's data model from its presentation, or queue animations. The internal state should update immediately, while rendering catches up.
  • Spherical linear interpolation (SLERP): For small angles, the standard slerp formula can produce NaNs due to division by zero. Instead of an arbitrary epsilon, check if dot(a, b) >= 1.f (or sin(angle) == 0.f) and switch to lerp in that specific, mathematically defined edge case.
  • Computing vector length: The naive sqrt(dot(v,v)) can return zero for very small non-zero vectors. A more robust method scales the vector by its largest coordinate (M) and checks M == 0.f to handle the true zero vector, avoiding NaNs and preserving precision.
  • Solving linear systems: Gaussian elimination can fail if a pivot is zero. Instead of an arbitrary epsilon for a near-zero pivot, check for M == 0.f. The algorithm should only fail when mathematically singular, not for arbitrary small values.
  • Ray-box intersection: The standard algorithm correctly handles direction.x == 0 (producing infinities) thanks to IEEE754 properties, which min/max functions can implicitly handle. The only unhandled case is 0/0 (NaN), which is extremely rare and can be explicitly checked.
  • Computing convex hull: Geometric predicates like left_turn are highly sensitive to floating-point errors, and arbitrary epsilons won't prevent invariants from breaking. More sophisticated methods like fixed grid rounding or arbitrary precision arithmetic are needed, not epsilons.

However, the article concedes that epsilons do have their place in two specific scenarios:

  • Sanitizing user input: When dealing with potentially messy user-provided polylines, filtering out points that are "too close" using an epsilon can prevent rendering artifacts, as the goal is visualization rather than strict mathematical precision. The epsilon should be derived from practical considerations like pixel size.
  • Writing test cases: Epsilon comparisons are useful in testing numerical libraries, as exact equality is often impractical due to inevitable floating-point inaccuracies. Separate, specialized tests should cover functional guarantees like a zero vector having zero length.

In conclusion, the author emphasizes that the decision to use or avoid epsilons should stem from critical thinking about the specific problem and the properties of floating-point numbers, rather than blindly following a dogma. While epsilons are often a poor substitute for robust algorithm design, they can be a pragmatic tool in specific, well-understood contexts.