Explain Codes LogoExplain Codes Logo

What's wrong with using == to compare floats in Java?

java
floating-point-precision
epsilon
best-practices
Alex KataevbyAlex Kataev·Jan 4, 2025
TLDR

Using == to compare floating point numbers in Java is not reliable due to binary representation inaccuracies. Instead, the safer approach is to see if the difference between the two numbers is small enough or within a specific tolerance level.

Example:

public static boolean closeEnough(float a, float b) { // not the Greek letter, but close enough final float EPSILON = 1E-6f; return Math.abs(a - b) < EPSILON; } // Usage // When in war, don't forget your float vests. System.out.println(closeEnough(0.2f, (0.2f + 0.1f - 0.1f))); // true if difference is within acceptable range

Key takeaways:

  • Precision issues might bite with binary floating-point
  • Use tolerance or EPSILON to keep precision errors at bay
  • Math.abs(a - b) < EPSILON: Always have this pattern in mind
  • Context-awareness is key when deciding EPSILON's value

Pitfalls of == for float comparison

The == operator in Java checks for exact bit-by-bit equality, leading to misleading results when used with floating point numbers. The reason lies in the rounding errors and approximations inherent to binary representation. For instance, the decimal number 0.1 cannot be perfectly represented in binary. This results in false negatives when comparing the results of arithmetic operations using ==.

Also, remember that the size of the epsilon value should be chosen judiciously based on the precision requirements of your specific task.

When epsilon is your best friend:

The epsilon value becomes a necessity in some special scenarios:

  • When complex calculations are involved
  • Working with geometric algorithms that can tolerate minor differences
  • Validating simulation results in scientific computations
  • Designing applications dealing with financial calculations where the difference of a cent matters but not that of a sub-cent fraction

There's not only one way to Rome:

Lest we forget, there are other respectable ways to compare floats:

  • Have a taste of wrapper classes and use equals() for exact equality
  • Try Float.compare() or Double.compare(). They consider special cases such as NaN and infinity

Decimal vs Binary: a love-hate relationship

In their internal binary representation, floating points adopt scientific notation leading to approximative representations. Example: 0.1 + 0.2 != 0.3 due to such binary rounding.

Shadows of floating-point comparison

Implicit casting can be a culprit when comparing different data types. Another facet to consider is that machine epsilon might vary from system to system and algorithm to algorithm, complicating the equation.

Trading off precision for Performance

For critical systems, you might have to make a decision between precision and performance. The use of an epsilon might be an additional overhead but is amendable to fine-tuning catering to precision needs.