avatar

Andres Jaimes

Quick lessons on working with Java’s BigDecimal

By Andres Jaimes

Today I bring an example of the different results you can expect when using Java’s BigDecimal class. From instantiation to applying different arithmetic operations, it is important to understand how they affect the resulting instances.

The following program shows different scenarios and results applied to BigDecimal’s.

package test;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Test {

    public static void main(String[] args) {
        BigDecimal a = new BigDecimal("1.204165");
        System.out.println("a (from string): " + a);
        // 1.204165
        
        a = new BigDecimal(1);
        System.out.println("a (from int): " + a);
        // 1
        
        a = new BigDecimal(1.204165);
        System.out.println("a (from float): " + a);
        // 1.2041649999999999298694319804781116545200347900390625
        
        a = a.setScale(6, RoundingMode.HALF_UP);
        System.out.println("a (setting scale): " + a);
        // 1.204165
        
        System.out.println("Add (1): " + a.add(new BigDecimal("0.0001")));
        // 1.204265
        
        System.out.println("Add (2): " + a.add(new BigDecimal(0.0001)));
        // 1.204265000000000000004792173602385929598312941379845142364501953125
        
        System.out.println("Add (3): " + a.add(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        // 1.204265
        
        System.out.println("Sub (1): " + a.subtract(new BigDecimal("0.0001")));
        // 1.204065
        
        System.out.println("Sub (2): " + a.subtract(new BigDecimal(0.0001)));
        // 1.204064999999999999995207826397614070401687058620154857635498046875
        
        System.out.println("Sub (3): " + a.subtract(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        // 1.204065
        
        System.out.println("Mult (1): " + a.multiply(new BigDecimal("0.0001")));
        // 0.0001204165
        
        System.out.println("Mult (2): " + a.multiply(new BigDecimal(0.0001)));
        // 0.000120416500000000005770567725917052914752503056661225855350494384765625
        
        System.out.println("Mult (3): " + a.multiply(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        // 0.000120416500
        
        System.out.println("Mult (4): " + a.multiply(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP));
        // 0.000120
        
        System.out.println("Mult (5): " + a.multiply(new BigDecimal(0.0001)).setScale(6, RoundingMode.HALF_UP));
        // 0.000120
        
        System.out.println("Div (1): " + a.divide(new BigDecimal("0.0001")));
        // 12041.65
        
        try {
            System.out.println("Div (2): " + a.divide(new BigDecimal(0.0001)));
        } catch (java.lang.ArithmeticException e) { System.out.println("Div (2): " + e.getMessage()); }
        // Non-terminating decimal expansion; no exact representable decimal result.
        
        System.out.println("Div (3): " + a.divide(new BigDecimal(0.0001), 6, RoundingMode.HALF_UP));
        // 12041.650000
        
        System.out.println("Div (4): " + a.divide(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        // 12041.65
        
        System.out.println("Div (5): " + a.divide(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP));
        // 12041.650000
        
        try {
            System.out.println("Div (6): " + a.divide(new BigDecimal(0.0001)).setScale(6, RoundingMode.HALF_UP));
        } catch (java.lang.ArithmeticException e) { System.out.println("Div (6): " + e.getMessage()); }
        // Non-terminating decimal expansion; no exact representable decimal result.
        
        System.out.println("Abs (1): " + a.abs());
        // 1.204165
        
        System.out.println("Abs (2): " + a.multiply(new BigDecimal("-1.0").setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP).abs());
        // 1.204165
    }
    
}

As you can see creating an instance from a String is the best way to get a BigDecimal when you want to keep certain precision. Rounding and scaling play as well an important role when making calculations with BigDecimal's.

It is worth keeping this example in mind specially in scenarios that involve currency operations, where the lack of rounding can easily generate unexpected results.