➗ Operators & Expressions · Beginner

Floating-point precision in Java

0.1 + 0.2 != 0.3, NaN != NaN, why money needs BigDecimal.

🧩 The mysteryAsk Java for 0.1 + 0.2 and it answers 0.30000000000000004. A bug? No, and understanding why will save your money code.

Binary can't write 0.1

float and double store numbers in binary. Just as 1/3 is 0.3333... forever in decimal, 0.1 is an endless pattern in binary. It gets rounded to the nearest double, leaving a tiny error.

🔮 Predict it

Your turn

What does this print?

System.out.println(0.1 + 0.2);
System.out.println(0.1 + 0.2 == 0.3);
  1. 0.3 true
  2. 0.30000000000000004 false
  3. 0.30000000000000004 true
Show the answer

The two tiny rounding errors add up, and the sum is a different double from 0.3. Java prints the shortest decimal that identifies that exact double: 0.30000000000000004.

Comparing doubles

✗ Fragile
if (a + b == 0.3) { ... }

Exact == fails over a difference in the 17th digit.

✓ Robust
if (Math.abs(a + b - 0.3) < 1e-9) { ... }

Compare within a small tolerance.

NaN isn't equal to itself

NaN ("not a number", e.g. 0.0 / 0.0) compares unequal to everything, even itself. So x == x is false when x is NaN. Test with Double.isNaN(x).

double nan = 0.0 / 0.0;
nan == nan          // false
Double.isNaN(nan)   // true

Money: BigDecimal

BigDecimal stores decimal digits exactly. Create it from a String (or with BigDecimal.valueOf), or count whole cents in a long.

var a = new BigDecimal("0.10");
var b = new BigDecimal("0.20");
a.add(b)    // 0.30, exactly
⚠️ The trap

new BigDecimal(0.1)

Passing a double copies its binary error into the BigDecimal, digit for digit. Always pass a String.

new BigDecimal(0.1)
// 0.1000000000000000055511151231257827
//   021181583404541015625
new BigDecimal("0.1")   // 0.1
🔮 Predict it

Your turn

With doubles, 0.7 + 0.1 gives 0.7999999999999999. What about BigDecimal?

var x = new BigDecimal("0.7");
var y = new BigDecimal("0.1");
System.out.println(x.add(y));
  1. 0.8
  2. 0.7999999999999999
  3. 0.80
Show the answer

BigDecimal works in decimal, so the sum is exactly 0.8. Both inputs have one digit after the point, so the result does too.

💼 In the real world

In real projects

Banks, shops and payment systems never store money in double. A fraction-of-a-cent drift, repeated over millions of transactions, breaks accounting. BigDecimal or whole cents in a long are the industry standard.

Key takeaways

  1. 0.1 + 0.2 is 0.30000000000000004
  2. Compare doubles with a tolerance, not ==
  3. NaN != NaN; use Double.isNaN(x)
  4. Money: new BigDecimal("0.10") or long cents
🤯 Did you know?

In 1991 a Patriot missile battery missed an incoming Scud: its clock counted tenths of a second, and 0.1 can't be stored exactly in binary. After 100 hours, the error had grown to about a third of a second.

Practice questions

What does this print?

System.out.println(0.1 + 0.2);
  1. 0.3
  2. 0.30000000000000001
  3. 0.299999999999999
  4. 0.30000000000000004
Check your answer

0.30000000000000004. Java prints the shortest decimal that uniquely identifies the double, and this sum is slightly more than 0.3.

What does this print?

double nan = 0.0 / 0.0;
System.out.println(nan == nan);
System.out.println(Double.isNaN(nan));
  1. true true
  2. true false
  3. false true
  4. false false
Check your answer

false true. By the IEEE 754 rules NaN compares unequal to everything, even itself. Double.isNaN is the reliable test.

Next: the Math class. Rounding, powers, roots, and a remainder that's never negative.