🔴 The Error You're Seeing

Confirm this matches your console output. If it does, you're in the right place.

ERROR LOGjava.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. at java.base/java.math.BigDecimal.divide(BigDecimal.java:1810)

⚡ Quick Fix Works 80% of the time

Always call divide with an explicit scale and rounding mode.

BigDecimal third = total.divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP);

🧠 Why this Happens

Tap to expand the deep technical explanation

BigDecimal represents exact fixed-point decimals. Its no-arg divide() promises the mathematical quotient EXACTLY; when the true expansion is infinite (most divisions, e.g. /3, /7), no finite digit string satisfies the promise, so divide() throws rather than choosing digits for you. Teams hit this migrating from double math (where 1.0/3 quietly became 0.333...) to BigDecimal for currency correctness.

The HITEC City Parking Spot Analogy:

Asked to write 1÷3 out IN FULL on a sticky note: the digits never end, so the writer gives up rather than lie about the last digit.

🔁 How to Reproduce Confirm this is your error

BigDecimal one = new BigDecimal("1"); one.divide(new BigDecimal("3")); // Non-terminating decimal expansion...

🛠️ Solutions (5 Ways to Fix)

Solution 1✓ Most common cause

Pass scale plus RoundingMode.HALF_UP

👉 Use this for money and reporting figures where two decimals are the contract.

Explicit scale makes every division terminate deterministically; HALF_UP matches common financial rounding expectations.

BigDecimal avg = revenue.divide(units, 2, RoundingMode.HALF_UP);
Solution 2

Use MathContext for scientific precision budgets

👉 Use this if values need significant-digit semantics rather than decimal places.

divide(divisor, MathContext.DECIMAL64) caps precision like a scientific calculator, trading exactness for guaranteed termination.

import java.math.MathContext; BigDecimal ratio = a.divide(b, MathContext.DECIMAL64);
Solution 3

Choose HALF_EVEN (banker rounding) for aggregates

👉 Use this if summing many rounded shares must not drift upward.

HALF_EVEN rounds ties to the nearest even digit, statistically canceling bias across thousands of splits - standard in payment ledgers.

amount.divide(count, 2, RoundingMode.HALF_EVEN)
Solution 4

Keep BigDecimal end-to-end, never round-trip through double

👉 Use this if fixing precision after discovering double drift.

Converting via double reintroduces binary-float noise (0.1 becomes 0.1000000000000000055...); parse from String or use BigDecimal.valueOf(double) only at boundaries.

BigDecimal d = BigDecimal.valueOf(0.1); // uses Double.toString canonical form BigDecimal s = new BigDecimal("0.1"); // preferred: exact literal
Solution 5

Pin known tricky quotients in tests

👉 Use this if finance calculations changed scales recently.

Asserting thirds, sevenths and repeating decimals locks scale/rounding policy into CI so refactors cannot silently change cents.

assertEquals(new BigDecimal("0.33"), new BigDecimal("1").divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP));

📋 Version Notes

Java 5+

Message and behavior stable since the BigDecimal rewrite.

Java 9+

Unchanged. Note pow() with huge exponents throws a sibling ArithmeticException when exceeding preferred precision without MathContext.

🛡️ How to Prevent This Next Time

Ban the one-arg divide() in review; make scale+RoundingMode mandatory wherever BigDecimal division appears.