BigDecimal

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 109 of 133

java.math.BigDecimal represents decimal numbers exactly. Where double stores a binary approximation of 0.1, a BigDecimal stores the digits 1 and the fact that they sit one place after the decimal point. Arithmetic on BigDecimal follows the decimal rules people use on paper, and rounding happens only where you ask for it, using a rounding mode you choose. This makes BigDecimal the standard type for money, prices, taxes, interest, and any calculation whose results must match an accountant's, a regulator's, or a customer's expectations to the last paisa.

Why double Is Not Suitable for Money

System.out.println(0.1 + 0.2);                                          // 0.30000000000000004
System.out.println(new BigDecimal("0.1").add(new BigDecimal("0.2")));   // 0.3

A tiny binary error in one calculation may look harmless, but invoices sum many items, apply percentages, and are compared against bank records. Errors accumulate, totals differ by a paisa from what a customer computes by hand, and equality checks fail. BigDecimal removes the problem at its source.

How BigDecimal Stores a Value

A BigDecimal is an unscaled value (an arbitrary-size integer) plus a scale (how many digits are after the decimal point):

123.45  =  unscaled value 12345,  scale 2
2.50    =  unscaled value 250,    scale 2
BigDecimal x = new BigDecimal("123.4500");
x.scale();        // 4: digits after the decimal point
x.precision();    // 7: total significant digits
x.unscaledValue();  // 1234500

Creating BigDecimals Correctly

BigDecimal a = new BigDecimal("1499.99");     // from a String: exact
BigDecimal b = BigDecimal.valueOf(1499);      // from a long: exact
BigDecimal c = BigDecimal.valueOf(0.1);       // from a double, via its shortest String form: 0.1
BigDecimal d = new BigDecimal(0.1);           // DON'T: captures the double's exact binary value
System.out.println(new BigDecimal(0.1));
// 0.1000000000000000055511151231257827021181583404541015625

The double constructor faithfully copies the binary approximation, which defeats the purpose. Create BigDecimal values from strings (or from integers), or use BigDecimal.valueOf(double) when a double is all you have.

Constants are available: BigDecimal.ZERO, ONE, TWO, TEN.

Immutability and Method-Based Arithmetic

Like BigInteger, BigDecimal is immutable and uses methods instead of operators. Every operation returns a new object:

BigDecimal price = new BigDecimal("79.50");
BigDecimal qty = BigDecimal.valueOf(3);

BigDecimal amount = price.multiply(qty);              // 238.50
BigDecimal withFee = amount.add(new BigDecimal("15")); // 253.50
BigDecimal diff = withFee.subtract(amount);           // 15.00

Forgetting to keep the result (amount.add(fee); on its own line) is the most common mistake.

Scales combine predictably: add and subtract use the larger scale; multiply adds the scales (79.50 × 3 = 238.50, scale 2 + 0).

Division Requires a Rounding Decision

Some divisions have no finite decimal result:

BigDecimal.ONE.divide(BigDecimal.valueOf(3));
// ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

Instead of silently approximating, BigDecimal makes you state the scale and rounding mode:

BigDecimal third = BigDecimal.ONE.divide(BigDecimal.valueOf(3), 4, RoundingMode.HALF_UP);   // 0.3333

Always pass a scale and RoundingMode (or a MathContext) to divide unless you are certain the result terminates.

Rounding with setScale

setScale(n, mode) rounds a value to n decimal places:

new BigDecimal("2.345").setScale(2, RoundingMode.HALF_UP);    // 2.35
ModeRule2.3452.355−2.345
HALF_UPRound half away from zero (school rounding)2.352.36−2.35
HALF_EVENRound half to the even neighbor ("banker's rounding")2.342.36−2.34
HALF_DOWNRound half toward zero2.342.35−2.34
DOWNTruncate toward zero2.342.35−2.34
UPAway from zero2.352.36−2.35
CEILINGToward +∞2.352.36−2.34
FLOORToward −∞2.342.35−2.35
UNNECESSARYThrow if rounding would be needed

HALF_UP matches what most people expect on invoices. HALF_EVEN avoids a systematic upward bias when rounding many values, which is why it is common in banking and statistics. The correct mode is often a business or legal rule (tax regulations frequently specify one), so make it an explicit, documented choice.

Comparing: compareTo, Not equals

equals compares both value and scale; compareTo compares numeric value only:

BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("2.00");

a.equals(b);             // false: different scales
a.compareTo(b) == 0;     // true: numerically equal

Use compareTo for numeric comparisons (> 0, < 0, == 0). The difference also affects collections: 2.0 and 2.00 are different keys in a HashMap or HashSet, but the same key in a TreeMap or TreeSet. Normalize first with setScale (or stripTrailingZeros()) if values from different sources will be compared or stored as keys.

Other comparison helpers: signum(), max(other), min(other), abs(), negate().

Displaying Values

new BigDecimal("2108.07").toPlainString();     // "2108.07"
new BigDecimal("1E+3").toString();             // "1E+3"   scientific form can appear
new BigDecimal("1E+3").toPlainString();        // "1000"
String.format("%,.2f", new BigDecimal("2108.07"));   // "2,108.07"
NumberFormat.getCurrencyInstance(Locale.forLanguageTag("en-IN")).format(new BigDecimal("2108.07"));  // ₹2,108.07

Use toPlainString() when sending values to other systems, since toString() may use exponent notation for some scales.

Performance and Alternatives

BigDecimal is much slower than double and creates many objects. For most business applications that cost is irrelevant compared with database and network time. Where performance matters greatly, a common alternative for money is a long holding the amount in the smallest currency unit (paise), with the conversion to rupees done only for display. Databases offer DECIMAL/NUMERIC columns, which JDBC maps to BigDecimal.

Practical Example: Invoice with GST and a Fair Split

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class BigD {
    static final BigDecimal GST = new BigDecimal("0.18");

    static List<BigDecimal> split(BigDecimal total, int people) {
        BigDecimal share = total.divide(BigDecimal.valueOf(people), 2, RoundingMode.DOWN);
        BigDecimal remainder = total.subtract(share.multiply(BigDecimal.valueOf(people)));
        List<BigDecimal> shares = new ArrayList<>();
        for (int i = 0; i < people; i++) {
            BigDecimal extra = remainder.compareTo(BigDecimal.ZERO) > 0 ? new BigDecimal("0.01") : BigDecimal.ZERO;
            shares.add(share.add(extra));
            remainder = remainder.subtract(extra);
        }
        return shares;
    }

    public static void main(String[] args) {
        record Line(String item, String price, int qty) { }
        List<Line> lines = List.of(new Line("Course: Java", "1499.00", 1), new Line("Notebook", "79.50", 3), new Line("Pen", "12.25", 4));
        BigDecimal subtotal = BigDecimal.ZERO;
        for (Line l : lines) {
            BigDecimal amount = new BigDecimal(l.price()).multiply(BigDecimal.valueOf(l.qty()));
            subtotal = subtotal.add(amount);
            System.out.printf("%-14s %8s x %d = %9s%n", l.item(), l.price(), l.qty(), amount);
        }
        BigDecimal tax = subtotal.multiply(GST).setScale(2, RoundingMode.HALF_UP);
        BigDecimal total = subtotal.add(tax);
        System.out.printf("%-26s %9s%n%-26s %9s%n%-26s %9s%n", "Subtotal", subtotal, "GST 18%", tax, "Total", total);
        System.out.println("Split 4 ways: " + split(total, 4));
    }
}

Output:

Course: Java    1499.00 x 1 =   1499.00
Notebook          79.50 x 3 =    238.50
Pen               12.25 x 4 =     49.00
Subtotal                     1786.50
GST 18%                       321.57
Total                        2108.07
Split 4 ways: [527.02, 527.02, 527.02, 527.01]

Every price is created from a String, so each line amount is exact. GST on 1,786.50 is exactly 321.570; setScale(2, HALF_UP) rounds it to paise at the single point where the business rule says rounding happens. The total therefore matches what a person would calculate by hand.

The split shows a classic money problem. ₹2,108.07 divided by 4 is 527.0175, which cannot be paid exactly. Rounding every share to 527.02 would collect 2,108.08, a paisa too much, and rounding down would collect 2,108.04, three paise short. split rounds each share down, computes the leftover (0.03), and adds one paisa to the first three shares, so the shares always add up to exactly the total. Payment systems use this same technique when dividing bills, EMIs, or refunds.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about BigDecimal and get answers drawn from it.

Signed-in readers only.