Quick lessons on working with Java’s BigDecimal

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);
        a = new BigDecimal(1);
        System.out.println("a (from int): " + a);
        a = new BigDecimal(1.204165);
        System.out.println("a (from float): " + a);
        a = a.setScale(6, RoundingMode.HALF_UP);
        System.out.println("a (setting scale): " + a);
        System.out.println("Add (1): " + a.add(new BigDecimal("0.0001")));
        System.out.println("Add (2): " + a.add(new BigDecimal(0.0001)));
        System.out.println("Add (3): " + a.add(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        System.out.println("Sub (1): " + a.subtract(new BigDecimal("0.0001")));
        System.out.println("Sub (2): " + a.subtract(new BigDecimal(0.0001)));
        System.out.println("Sub (3): " + a.subtract(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        System.out.println("Mult (1): " + a.multiply(new BigDecimal("0.0001")));
        System.out.println("Mult (2): " + a.multiply(new BigDecimal(0.0001)));
        System.out.println("Mult (3): " + a.multiply(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        System.out.println("Mult (4): " + a.multiply(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP));
        System.out.println("Mult (5): " + a.multiply(new BigDecimal(0.0001)).setScale(6, RoundingMode.HALF_UP));
        System.out.println("Div (1): " + a.divide(new BigDecimal("0.0001")));
        try {
            System.out.println("Div (2): " + a.divide(new BigDecimal(0.0001)));
        } catch (java.lang.ArithmeticException e) { System.out.println("Div (2): " + e.getMessage()); }
        System.out.println("Div (3): " + a.divide(new BigDecimal(0.0001), 6, RoundingMode.HALF_UP));
        System.out.println("Div (4): " + a.divide(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
        System.out.println("Div (5): " + a.divide(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP));
        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()); }
        System.out.println("Abs (1): " + a.abs());
        System.out.println("Abs (2): " + a.multiply(new BigDecimal("-1.0").setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP).abs());
    }
    
}

After running the application you can see the different results obtained.

a (from string): 1.204165
a (from int): 1
a (from float): 1.2041649999999999298694319804781116545200347900390625
a (setting scale): 1.204165
Add (1): 1.204265
Add (2): 1.204265000000000000004792173602385929598312941379845142364501953125
Add (3): 1.204265
Sub (1): 1.204065
Sub (2): 1.204064999999999999995207826397614070401687058620154857635498046875
Sub (3): 1.204065
Mult (1): 0.0001204165
Mult (2): 0.000120416500000000005770567725917052914752503056661225855350494384765625
Mult (3): 0.000120416500
Mult (4): 0.000120
Mult (5): 0.000120
Div (1): 12041.65
Div (2): Non-terminating decimal expansion; no exact representable decimal result.
Div (3): 12041.650000
Div (4): 12041.65
Div (5): 12041.650000
Div (6): Non-terminating decimal expansion; no exact representable decimal result.
Abs (1): 1.204165
Abs (2): 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.

Leave a Reply