89. Floating-Point Equality
Never use == to compare double or float values; 0.1 + 0.2 != 0.3 because of IEEE 754 binary representation; use a tolerance comparison or BigDecimal for exact decimal arithmetic (e.g., money).
Explanation
IEEE 754 binary floating-point cannot represent many decimal fractions exactly. 0.1 in binary is a repeating fraction โ the stored value is slightly off. Arithmetic on these inexact values accumulates error, so 0.1 + 0.2 evaluates to 0.30000000000000004, not 0.3.
For comparisons: use Math.abs(a - b) < epsilon where epsilon is an appropriate tolerance for your domain. There is no single right epsilon โ choose based on the magnitude of the values and the acceptable error.
For money and exact decimal arithmetic: use java.math.BigDecimal. It stores decimal numbers exactly (as arbitrary-precision decimal strings) and supports exact addition, subtraction, multiplication, and division (with explicit rounding modes). Never store money as double โ you will have rounding errors in cents.
Example
import java.math.BigDecimal;
import java.math.RoundingMode;
public class FloatingPointEquality {
public static void main(String[] args) {
// The classic trap
double a = 0.1 + 0.2;
double b = 0.3;
System.out.println("0.1 + 0.2 == 0.3 : " + (a == b)); // false!
System.out.printf( "0.1 + 0.2 = %.17f%n", a); // 0.30000000000000004
System.out.printf( "0.3 = %.17f%n", b); // 0.29999999999999999
// Tolerance comparison
double EPSILON = 1e-9;
System.out.println("Approx equal: " + (Math.abs(a - b) < EPSILON)); // true
// Double.compare: handles NaN and -0.0 correctly
double x = 1.0 / 3.0;
double y = 1.0 / 3.0;
System.out.println("Double.compare: " + (Double.compare(x, y) == 0)); // true (same computation)
// NaN traps
double nan = Double.NaN;
System.out.println("NaN == NaN: " + (nan == nan)); // false! (IEEE 754)
System.out.println("Double.isNaN: " + Double.isNaN(nan)); // true (correct check)
// -0.0 == 0.0 but they differ in IEEE 754
System.out.println("-0.0 == 0.0: " + (-0.0 == 0.0)); // true!
// MONEY: use BigDecimal for exact decimal arithmetic
BigDecimal price = new BigDecimal("19.99");
BigDecimal tax = new BigDecimal("0.08");
BigDecimal total = price.multiply(BigDecimal.ONE.add(tax))
.setScale(2, RoundingMode.HALF_UP);
System.out.println("Price with tax: $" + total); // $21.59
BigDecimal tenth = new BigDecimal("0.1");
BigDecimal twoTenths = new BigDecimal("0.2");
System.out.println("0.1 + 0.2 (BD): " + tenth.add(twoTenths)); // 0.3 exactly
System.out.println("Equal (BD): " + tenth.add(twoTenths).compareTo(new BigDecimal("0.3")) == 0); // true
}
}Sources
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/math/BigDecimal.html โ BigDecimal API
- https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html โ Primitive data types