Medium🚨 Your Java Money Calculation Is Wrong — Stop Using double for Currency | by Lakshika | Oct, 2026 | Stackademic
Sitemap
Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.

🚨 Your Java Money Calculation Is Wrong — Stop Using double for Currency

4 min readOct 5, 2026

--

This Java code looks harmless:

double price = 0.1;
double tax = 0.2;
System.out.println(price + tax);

You might expect:

0.3

But Java can print something like:

0.30000000000000004

For scientific calculations, tiny floating-point differences may be acceptable.

For:

Money
Payments
Invoices
Tax
Interest
Accounting

they can become real bugs.

1. Why Does This Happen?

double uses binary floating-point representation.

Some decimal values cannot be represented exactly in binary.

Conceptually:

0.1
looks simple in decimal
but cannot be represented
exactly as a finite binary value

So Java stores a nearby approximation.

Then calculations can expose the difference.

2. The Dangerous Payment Code

Imagine:

double price = 199.99;
double taxRate = 0.18;
double tax = price * taxRate;
double total = price + tax;

Looks perfectly normal.

Now imagine doing similar calculations for:

1 transaction
100 transactions
1,000,000 transactions

Rounding decisions start to matter.

Especially when totals must match:

Payment gateway
Invoice
Database
Accounting system
Refund calculation

A one-cent/one-paise disagreement can become a reconciliation problem.

3. Never Compare Money Like This

Another common bug:

double expected = 0.3;
double actual = 0.1 + 0.2;
if (expected == actual) {
System.out.println("MATCH");
}

The result may surprise you.

expected
0.3
actual
0.30000000000000004

So:

expected == actual

can be:

false

Not what you want for financial business logic.

4. Use BigDecimal

For decimal financial calculations, Java provides:

BigDecimal

Example:

BigDecimal price =
new BigDecimal("0.1");
BigDecimal tax =
new BigDecimal("0.2");
BigDecimal total =
price.add(tax);
System.out.println(total);

Result:

0.3

Much better for decimal money calculations.

5. But There’s Another Trap

Don’t do this:

BigDecimal amount =
new BigDecimal(0.1);

You may carry the floating-point approximation into your BigDecimal.

Prefer:

new BigDecimal("0.1")

or:

BigDecimal.valueOf(0.1)

For fixed application values, string construction is very explicit.

6. Money Needs a Rounding Rule

Suppose:

BigDecimal amount =
new BigDecimal("100");
BigDecimal divisor =
new BigDecimal("3");

This:

amount.divide(divisor);

cannot produce a finite decimal result without a rounding decision.

So define one explicitly.

BigDecimal result =
amount.divide(
divisor,
2,
RoundingMode.HALF_UP
);

Result:

33.33

But the important point isn’t that HALF_UP is always correct.

The important point is:

Your business must define the rounding policy.

7. Different Businesses Need Different Rules

You might need:

HALF_UP
HALF_EVEN
DOWN
UP

depending on:

Currency rules
Tax rules
Banking rules
Accounting requirements
Business contracts

Don’t scatter random rounding logic throughout the codebase.

Centralize it.

8. Be Careful With Scale

These values are numerically equal:

10.0
10.00

But BigDecimal has both:

Value
+
Scale

That creates an important Java trap.

BigDecimal a =
new BigDecimal("10.0");
BigDecimal b =
new BigDecimal("10.00");
System.out.println(a.equals(b));

This returns:

false

because equals() considers scale.

Get Lakshika’s stories in your inbox

Join Medium for free to get updates from this writer.

But:

a.compareTo(b)

returns:

0

meaning the numerical values are equal.

9. Don’t Compare Money With equals() Blindly

Instead of:

if (amount.equals(expected)) {
...
}

you may want numerical comparison:

if (amount.compareTo(expected) == 0) {
...
}

depending on your domain requirements.

This tiny difference causes surprisingly confusing bugs.

10. Create a Clear Money Model

Instead of passing random BigDecimal values everywhere:

BigDecimal amount

consider modeling money explicitly.

For example:

public record Money(
BigDecimal amount,
Currency currency) {
}

Now:

100 USD

is different from:

100 INR

because:

Amount alone ≠ Money

Currency matters too.

11. Store Money Carefully in the Database

Avoid:

price DOUBLE

for exact decimal financial values.

A common relational database choice is:

price DECIMAL(19, 4)

or an appropriate precision and scale for your domain.

Then your application can map it to:

BigDecimal

Your precision and scale should reflect actual business requirements.

12. Another Good Strategy: Minor Units

Some systems store money in the smallest currency unit.

Instead of:

₹199.99

store:

19999 paise

using an integer type.

Conceptually:

long amountInPaise = 19999;

This can simplify some payment systems.

But remember:

Not every currency uses exactly two decimal places.

So don’t hardcode assumptions like:

Every currency = 100 minor units

unless your system supports only currencies where that’s valid.

13. Example: Better Checkout Calculation

Instead of:

double subtotal = 999.99;
double tax =
subtotal * 0.18;
double total =
subtotal + tax;

use:

BigDecimal subtotal =
new BigDecimal("999.99");
BigDecimal taxRate =
new BigDecimal("0.18");
BigDecimal tax =
subtotal
.multiply(taxRate)
.setScale(
2,
RoundingMode.HALF_UP
);
BigDecimal total =
subtotal.add(tax);

Now the rounding decision is visible.

That’s important.

14. Before vs After

❌ Risky

double
0.1
+
0.2
↓
0.30000000000000004
↓
Rounding surprises
↓
Invoice mismatch

✅ Better

BigDecimal
"0.1"
+
"0.2"
↓
0.3
↓
Explicit rounding
↓
Predictable financial logic

15. Production Checklist

Search your financial code for:

✓ double price
✓ double amount
✓ double tax
✓ double balance
✓ double interest
✓ float money

Then check:

✓ Are we using BigDecimal?
✓ Are values constructed safely?
✓ Is rounding explicit?
✓ Is rounding centralized?
✓ Is scale defined?
✓ Are BigDecimals compared correctly?
✓ Is currency stored with the amount?
✓ Does DB precision match Java?
✓ Are external payment amounts converted safely?
✓ Have boundary cases been tested?

🔥 Final Takeaway

double isn't broken.

It’s simply designed for floating-point arithmetic where binary approximation is expected.

Financial systems often need something different:

Exact decimal representation
+
Explicit rounding
+
Clear currency rules

So don’t write:

double money;

just because money contains decimals.

Choose a representation that matches the business requirement.

One-Line Wisdom

Money isn’t just a number with decimals — it’s a value with precision, rounding rules, and a currency.

--

--

Written by Lakshika

Spring Boot Developer | Writing about Java, Backend Architecture & Real-World System Design

Published in Stackademic

Stackademic is a learning hub for programmers, devs, coders, and engineers. Our goal is to democratize free coding education for the world.