🧰 Core APIs Toolbox · Intermediate

BigDecimal for money in Java

Exact decimal math, new BigDecimal("0.1") vs (0.1), compareTo vs equals, scale and RoundingMode.

🧩 The mysteryYour shopping cart adds 0.1 + 0.2 and charges the customer 0.30000000000000004. Somewhere, an accountant screams. How do you make Java count money like a cashier?

Counting money in coins

double stores numbers as binary fractions. Just as 1/3 can't be written exactly in decimal (0.333…), 0.1 can't be written exactly in binary, so tiny errors creep in. **BigDecimal stores an exact decimal number** — like counting real coins instead of estimating.

🔮 Predict it

The famous sum

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

0.30000000000000004 and false — binary rounding errors. With new BigDecimal("0.1").add(new BigDecimal("0.2")) you get exactly **0.3**.

Building a BigDecimal

✗ From a double
new BigDecimal(0.1)
// 0.1000000000000000055511151231257827…

The double 0.1 is already slightly off, and this constructor copies that error exactly.

✓ From a String
new BigDecimal("0.1")   // exactly 0.1
BigDecimal.valueOf(0.1) // also 0.1

Strings are exact. valueOf goes through the double's short text form, so it's fine too.

Scale, equals and compareTo

The scale is the number of digits after the point: 2.0 has scale 1, 2.00 scale 2. **equals compares value AND scale, so they're *not* equal! compareTo compares only the numeric value** — use it to compare amounts.

var a = new BigDecimal("2.0");
var b = new BigDecimal("2.00");
a.equals(b);         // false (scale 1 vs 2)
a.compareTo(b) == 0; // true
🔮 Predict it

Equal or not?

What does this print?

var x = new BigDecimal("1.50");
var y = new BigDecimal("1.5");
System.out.println(x.equals(y));
System.out.println(x.compareTo(y));
  1. true 0
  2. false 0
  3. false 1
Show the answer

false then 0 — different scales make equals false, while compareTo returns 0 for the same numeric value.

Rounding on purpose

setScale(2, mode) rounds to 2 decimals using a **RoundingMode you choose. HALF_UP rounds ties up (school rounding). HALF_EVEN (banker's rounding) rounds ties to the even** neighbour, which avoids bias over many sums.

var x = new BigDecimal("0.125");
x.setScale(2, RoundingMode.HALF_UP);   // 0.13
x.setScale(2, RoundingMode.HALF_EVEN); // 0.12
⚠️ The trap

Dividing into infinity

1 ÷ 3 = 0.333… has no exact decimal form, so divide without a scale throws **ArithmeticException ("Non-terminating decimal expansion"). Give it a scale and a RoundingMode**.

var total = new BigDecimal("1.00");
var three = new BigDecimal("3");
total.divide(three);  // ArithmeticException
total.divide(three, 2, RoundingMode.HALF_UP);
// 0.33
💼 In the real world

Money in production

Banks, payment providers and e-commerce backends use BigDecimal (or integer cents) for every amount. Splitting a bill, applying tax, converting currency — each needs an explicit scale and RoundingMode, and auditors will ask which one you chose.

Key takeaways

  1. new BigDecimal("0.1") is exact; new BigDecimal(0.1) is not
  2. equals checks value AND scale: 2.0 ≠ 2.00
  3. compareTo checks only the numeric value
  4. divide may need a scale and RoundingMode
🤯 Did you know?

new BigDecimal(0.1) prints 0.1000000000000000055511151231257827021181583404541015625 — that's the exact value the double 0.1 really holds.

Practice questions

What does this print?

System.out.println(0.1 + 0.2);
System.out.println(new BigDecimal("0.1")
    .add(new BigDecimal("0.2")));
  1. 0.3 0.3
  2. 0.30000000000000004 0.3
  3. 0.30000000000000004 0.30000000000000004
  4. 0.3 0.30000000000000004
Check your answer

0.30000000000000004 0.3. double addition shows binary rounding error, while BigDecimal built from strings adds exact decimals.

What does this print?

BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("2.00");
System.out.println(a.equals(b));
System.out.println(a.compareTo(b) == 0);
  1. true true
  2. false false
  3. false true
  4. true false
Check your answer

false true. BigDecimal.equals also compares the scale (1 vs 2 decimal places), so it's false. compareTo compares only the numeric value.

Next: integers with no ceiling. What happens when you add 1 to the biggest long… with BigInteger?