Java introduction to BigDecimal

BigDecimal represent immutable, arbitrary-precision signed decimal numbers. A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale.

The BigDecimal class provides operations for arithmetic, scale manipulation, rounding, comparison, hashing, and format conversion. The toString() method provides a canonical representation of a BigDecimal.

Why we need BigDecimal? We already have double, float and their classes Double and Float. It is hard to represent many decimal numbers. If in mathematics it is easy to write 10/3 to actually show it is quite a challenge. Also humans work with decimal system but the computer work in binary system which mean that the computer will struggle to represent numbers which for us humans looks normal.

import java.math.BigDecimal;

public class MainBigDecimalTest {
    public static void main(String[] args) {
        double d1 = 2.0;
        double d2 = 2.63;

        double result = d2 - d1;
        System.out.println("result: " + result);
    }
}

Output:

result: 0.6299999999999999

Now there are ways to minimize this errors and one of them is to use BigDecimal class.

Same calculation with BigDecimal:

import java.math.BigDecimal;

public class MainBigDecimalTest {
    public static void main(String[] args) {
        BigDecimal d1 = new BigDecimal("2.0");
        BigDecimal d2 = new BigDecimal("2.63");
        
        BigDecimal result = d2.subtract(d1);
        System.out.println("result: " + result);
    }
}

Output:

result: 0.63

So why we have float and decimal at all? Because calculations done with them are fast and it is normal for certain calculation not to be precise.

Lets look again the previous value of decimal: 0.6299999999999999 The major problem here is the rounding, right? So we can write also the program like this:

public class MainBigDecimalTest {
    public static void main(String[] args) {
        double d1 = 2.0;
        double d2 = 2.63;

        double result = d2 - d1;
        System.out.printf("result: %%.2f", result);
    }
}

Output:

result: 0.63

Even with a small error if we round up to the two numbers after the decimal sign we get the value which we expect.

But there are calculations for example in the finance sector where we should not make even small error. There using BigDecimal is a must. Remember in such case do not change to Double or Float before or after calculations with BigDecimal because creating object from Double or Float already can introduce this loss of precision. One good way to create BigDecimal is with the constructors which accept String. There we can add the exact number that we want. For example BigDecimal d2 = new BigDecimal(“2.63”);

When we need to compare of BigDecimals never use equals because equals will consider also the scale and we don’t need the scale to be considered when check for number equality. Always use compareTo method instead.

import java.math.BigDecimal;

public class MainBigDecimalTest {
    public static void main(String[] args) {
        BigDecimal d1 = new BigDecimal("2.00");
        BigDecimal d2 = new BigDecimal("2");

        // equals also consider the scale
        System.out.println(d1.equals(d2));

        // compare == 0 means that the two numbers are equal
        System.out.println(d1.compareTo(d2) == 0);
    }
}

Output:

false
true

BigDecimal rounding. In some cases we need to round result. There is different rounding modes depending of our requirements.

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

public class MainBigDecimalTest {
    public static void main(String[] args) {
        BigDecimal d1 = new BigDecimal("1.9534");
        BigDecimal result1 = d1.setScale(2, RoundingMode.HALF_EVEN);
        System.out.println("result1: " + result1);

        BigDecimal d2 = new BigDecimal("1.9554");
        BigDecimal result2 = d2.setScale(2, RoundingMode.HALF_EVEN);
        System.out.println("result2: " + result2);

        // There is different RoundingMode depending on our requirements.
        BigDecimal result3 = d2.setScale(2, RoundingMode.DOWN);
        System.out.println("result3: " + result3);
    }
}

Output:

result1: 1.95
result2: 1.96
result2: 1.95

Leave a Comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.