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.

 1package test;
 2
 3import java.math.BigDecimal;
 4import java.math.RoundingMode;
 5
 6public class Test {
 7
 8    public static void main(String[] args) {
 9        BigDecimal a = new BigDecimal("1.204165");
10        System.out.println("a (from string): " + a);
11        // 1.204165
12        
13        a = new BigDecimal(1);
14        System.out.println("a (from int): " + a);
15        // 1
16        
17        a = new BigDecimal(1.204165);
18        System.out.println("a (from float): " + a);
19        // 1.2041649999999999298694319804781116545200347900390625
20        
21        a = a.setScale(6, RoundingMode.HALF_UP);
22        System.out.println("a (setting scale): " + a);
23        // 1.204165
24        
25        System.out.println("Add (1): " + a.add(new BigDecimal("0.0001")));
26        // 1.204265
27        
28        System.out.println("Add (2): " + a.add(new BigDecimal(0.0001)));
29        // 1.204265000000000000004792173602385929598312941379845142364501953125
30        
31        System.out.println("Add (3): " + a.add(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
32        // 1.204265
33        
34        System.out.println("Sub (1): " + a.subtract(new BigDecimal("0.0001")));
35        // 1.204065
36        
37        System.out.println("Sub (2): " + a.subtract(new BigDecimal(0.0001)));
38        // 1.204064999999999999995207826397614070401687058620154857635498046875
39        
40        System.out.println("Sub (3): " + a.subtract(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
41        // 1.204065
42        
43        System.out.println("Mult (1): " + a.multiply(new BigDecimal("0.0001")));
44        // 0.0001204165
45        
46        System.out.println("Mult (2): " + a.multiply(new BigDecimal(0.0001)));
47        // 0.000120416500000000005770567725917052914752503056661225855350494384765625
48        
49        System.out.println("Mult (3): " + a.multiply(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
50        // 0.000120416500
51        
52        System.out.println("Mult (4): " + a.multiply(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP));
53        // 0.000120
54        
55        System.out.println("Mult (5): " + a.multiply(new BigDecimal(0.0001)).setScale(6, RoundingMode.HALF_UP));
56        // 0.000120
57        
58        System.out.println("Div (1): " + a.divide(new BigDecimal("0.0001")));
59        // 12041.65
60        
61        try {
62            System.out.println("Div (2): " + a.divide(new BigDecimal(0.0001)));
63        } catch (java.lang.ArithmeticException e) { System.out.println("Div (2): " + e.getMessage()); }
64        // Non-terminating decimal expansion; no exact representable decimal result.
65        
66        System.out.println("Div (3): " + a.divide(new BigDecimal(0.0001), 6, RoundingMode.HALF_UP));
67        // 12041.650000
68        
69        System.out.println("Div (4): " + a.divide(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)));
70        // 12041.65
71        
72        System.out.println("Div (5): " + a.divide(new BigDecimal(0.0001).setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP));
73        // 12041.650000
74        
75        try {
76            System.out.println("Div (6): " + a.divide(new BigDecimal(0.0001)).setScale(6, RoundingMode.HALF_UP));
77        } catch (java.lang.ArithmeticException e) { System.out.println("Div (6): " + e.getMessage()); }
78        // Non-terminating decimal expansion; no exact representable decimal result.
79        
80        System.out.println("Abs (1): " + a.abs());
81        // 1.204165
82        
83        System.out.println("Abs (2): " + a.multiply(new BigDecimal("-1.0").setScale(6, RoundingMode.HALF_UP)).setScale(6, RoundingMode.HALF_UP).abs());
84        // 1.204165
85    }
86    
87}

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.