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);
// 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.