Java BigDecimal Add, Subtract, Multiply, Divide
java bigdecimal add subtract multiply divide: How to use Java BigDecimal add, subtract, multiply, and divide for exact decimal arithmetic, including scale handling, ro...
Java's BigDecimal class is the standard tool when you need exact decimal arithmetic. The four core operations — add, subtract, multiply, and divide — cover most financial and measurement calculations, but they do not behave identically. Understanding how java bigdecimal add subtract multiply divide works, especially around scale and rounding, is what separates correct code from code that fails only on certain inputs.
Why BigDecimal Instead of double or float
The double and float types store numbers in binary floating-point form. Values like 0.1 cannot be represented exactly, so operations such as 0.1 + 0.2 produce 0.30000000000000004. For most scientific and graphics work this is acceptable. For monetary totals, tax calculations, or any value that must match a printed decimal, the error is a bug.
BigDecimal stores a decimal value as an unscaled integer and a scale. The scale is the number of digits to the right of the decimal point. This representation makes arithmetic exact as long as you control the scale and rounding behavior explicitly.
BigDecimal a = new BigDecimal("0.1"); BigDecimal b = new BigDecimal("0.2"); BigDecimal sum = a.add(b); // 0.3 exactly
Notice the constructor takes a String. Using new BigDecimal(0.1) passes the binary double 0.1, which is not exactly 0.1, and the resulting BigDecimal carries that error. Always construct BigDecimal from a String or from an integer when you need exact decimal values.
The Core Arithmetic Methods: add, subtract, multiply
The add, subtract, and multiply methods are straightforward. Each returns a new BigDecimal and leaves the receiver unchanged, because BigDecimal is immutable.
BigDecimal price = new BigDecimal("19.99"); BigDecimal quantity = new BigDecimal("3"); BigDecimal lineTotal = price.multiply(quantity); // 59.97
BigDecimal balance = new BigDecimal("1000.00"); BigDecimal deposit = new BigDecimal("250.50"); BigDecimal withdrawal = new BigDecimal("120.25"); BigDecimal afterDeposit = balance.add(deposit); // 1250.50 BigDecimal finalBalance = afterDeposit.subtract(withdrawal); // 1130.25
The scale of the result follows predictable rules. For add and subtract, the result scale is the maximum of the two operand scales. For multiply, the result scale is the sum of the operand scales. So 19.99 (scale 2) times 3 (scale 0) yields 59.97 (scale 2). These rules mean you rarely need to adjust the result of add, subtract, or multiply — the exact value is preserved.
Divide: The Operation That Requires a Decision
The divide method is different. Dividing two integers such as 10 by 3 produces a non-terminating decimal expansion. BigDecimal cannot represent that exactly, so the default divide method throws ArithmeticException with a message about non-terminating decimal expansion.
BigDecimal ten = new BigDecimal("10"); BigDecimal three = new BigDecimal("3"); // Throws ArithmeticException // BigDecimal result = ten.divide(three);
To divide safely, you must tell BigDecimal how many digits to keep and how to round. The simplest form passes a scale and a RoundingMode:
BigDecimal result = ten.divide(three, 2, RoundingMode.HALF_UP); // 3.33
The scale argument is the number of fractional digits in the result. The RoundingMode determines how the discarded digits are handled. Choosing the right rounding mode matters for financial correctness, which is why the method forces you to be explicit.
Choosing Scale and Rounding Mode
The RoundingMode enum provides eight modes. The most common choices for financial arithmetic are HALF_UP and HALF_EVEN.
| RoundingMode | Behavior |
|---|---|
| HALF_UP | Rounds to nearest neighbor; ties round away from zero |
| HALF_DOWN | Rounds to nearest neighbor; ties round toward zero |
| HALF_EVEN | Rounds to nearest neighbor; ties round to even neighbor |
| UP | Rounds away from zero |
| DOWN | Rounds toward zero |
| CEILING | Rounds toward positive infinity |
| FLOOR | Rounds toward negative infinity |
HALF_UP is the familiar schoolbook rounding used in most currency calculations. HALF_EVEN, sometimes called banker's rounding, avoids the upward bias that HALF_UP introduces when many values end in exactly 5. Accounting systems sometimes require HALF_EVEN for that reason. Choose the mode that matches your business rules rather than defaulting to whatever is convenient.
An alternative to passing scale and mode on every call is to use a MathContext, which bundles precision and rounding mode:
MathContext mc = new MathContext(4, RoundingMode.HALF_UP); BigDecimal result = ten.divide(three, mc); // 3.333
Note that MathContext precision counts total significant digits, not fractional digits. A precision of 4 on 10 / 3 produces 3.333, while a scale of 2 produces 3.33. Confusing the two is a common source of off-by-one errors.
Chaining Operations and Immutability
Because every arithmetic method returns a new BigDecimal, you can chain operations in a single expression. This is readable and safe, since no intermediate value is mutated.
BigDecimal price = new BigDecimal("49.99"); BigDecimal quantity = new BigDecimal("2"); BigDecimal taxRate = new BigDecimal("0.08"); BigDecimal discount = new BigDecimal("5.00"); BigDecimal subtotal = price.multiply(quantity); // 99.98 BigDecimal tax = subtotal.multiply(taxRate); // 7.9984 BigDecimal total = subtotal.add(tax).subtract(discount); // 102.9784
The immutability also means you can safely share a BigDecimal instance across threads. No operation modifies the internal state, so concurrent reads of the same instance are safe. This is a real advantage over mutable numeric types in concurrent code.
Performance and Memory Considerations
Every add, subtract, multiply, or divide call allocates a new BigDecimal object. In a loop that performs thousands of arithmetic operations, this allocation pressure is measurable, though usually minor compared to I/O or database work. The cost is not the arithmetic itself but object creation and garbage collection.
For high-frequency numeric loops where exact decimal values are not required, double is faster and uses less memory. Use BigDecimal when the decimal result must be exact or when rounding behavior must be controlled — for example, in financial calculations, invoice totals, or currency conversion. Do not use it for counters, indexes, or performance-critical scientific loops where binary floating point is acceptable.
If you must perform many BigDecimal operations, consider whether the scale can be kept small. Larger scales mean larger internal representations, which increases the cost of each operation. Keeping values at the smallest scale your business logic requires reduces that overhead.
Common Mistakes and Edge Cases
The most common failure is calling divide without a scale or MathContext. The resulting ArithmeticException only appears at runtime for inputs that produce non-terminating decimals, so it can pass tests with one set of values and fail in production with another. Always specify scale and rounding mode.
Comparing BigDecimal values with equals() can also surprise you. equals() considers scale, so new BigDecimal("2.0") and new BigDecimal("2.00") are not equal even though they represent the same numeric value. Use compareTo() when you care about numeric equality:
BigDecimal x = new BigDecimal("2.0"); BigDecimal y = new BigDecimal("2.00"); x.equals(y); // false x.compareTo(y); // 0
Dividing by zero throws ArithmeticException regardless of scale or rounding mode, so guard against zero denominators before calling divide.
Finally, remember that the constructor from double carries binary floating-point error into the BigDecimal. new BigDecimal(0.1) produces a value slightly larger than 0.1. Use the String constructor for values that must be exact, or BigDecimal.valueOf(double) when you must convert a double that already represents a clean decimal.