You are currently viewing BigDecimal Class In Java

BigDecimal Class In Java

1. Introduction

Are you planning to write a Java program that requires total control over the scaling of decimal numbers? BigDecimal is the class you need to deal with. In this tutorial, you will learn what a BigDecimal is. You’ll also learn some operations you can perform on BigDecimals and common use cases where you should go for BigDecimal instead of the traditional Double class.

2. How to Create a BigDecimal

According to its Javadoc, a BigDecimal represents an immutable, arbitrary-precision decimal number. A BigDecimal consists of an arbitrary-precision integer unscaled value and a 32-bit integer scale.

There are two main ways of creating a BigDecimal: using constructors and using static methods BigDecimal#valueOf().

2.1. BigDecimal Constructors

BigDecimal offers multiple constructors with different parameter types: BigInteger, long, double, char, String, etc. Some of the constructors also accept a MathContext object which provides a way to specify the scale and the rounding mode. In this section, we will provide some of the most used constructors.

2.1.1. BigDecimal(double val)

This code will construct a BigDecimal object from the double value 1.5.

        BigDecimal bigDecimal = new BigDecimal(1.5);
        System.out.println(bigDecimal);

Output:

1.5

However, this way of creating a BigDecimal might produce unexpected output because the value passed to the constructor needs to be converted to a floating-point first. This conversion to a floating-point number may lead to a precision issue.
To understand this issue, try to execute the following code:

        BigDecimal bigDecimal = new BigDecimal(0.1);
        System.out.println(bigDecimal);

Output:

0.1000000000000000055511151231257827021181583404541015625

As you can see, the output is not what you could have expected (0.1). This is because the value “0.1” cannot be translated into an exact floating-point number. Instead, an approximated value is returned.

For this reason, it is recommended to use the String constructor because it does not require an intermediate conversion to a floating-point number.

2.1.2. BigDecimal(String val)

This is the recommended way of creating a BigDecimal, especially if the source value is a floating-point number (double or float).

        BigDecimal bigDecimal = new BigDecimal("0.1");
        System.out.println(bigDecimal);

Output:

0.1

As you can see, with this constructor you obtain the exact representation of the String value.

2.1.3. BigDecimal(String val, MathContext mc)

Optionally, we may need the value to be with a specific precision. In that case, you must provide a MathContext object along with the String parameter.
In the following example, we create a MathContext object with a precision of 3 significant digits.

        MathContext mc = new MathContext(3);
        BigDecimal bigDecimal = new BigDecimal("0.1", mc);
        System.out.println(bigDecimal);

Output:

0.10

As a result, the displayed value has 2 digits after the decimal symbol.

2.2. BigDecimal#valueOf()

Java also provides static factory methods to create a BigDecimal from a BigInteger, a double, or a long. You should prefer these methods when converting primitive types (long, double) or BigIntegers to BigDecimals. The reason is that these methods ensure that the conversion maintains precision and prevents you from the pitfalls due to floating-point arithmetic.

2.2.1. BigDecimal#valueOf(double)

        BigDecimal value = BigDecimal.valueOf(0.1);
        System.out.println(value);

Output:

0.1

2.2.2. BigDecimal#valueOf(long)

        BigDecimal value = BigDecimal.valueOf(10L);
        System.out.println(value);

Output:

10

3. Arithmetic Operations

You can perform the usual arithmetic operations on BigDecimals, including addition, subtraction, multiplication, and division. Since BigDecimal is an immutable class, all these operations return the result in a new object.

3.1. Addition

The following code will return a new BigDecimal whose value is myValue + toAdd.

        BigDecimal myValue = new BigDecimal("1.5");
        BigDecimal toAdd = new BigDecimal("0.50");
        BigDecimal result = myValue.add(toAdd);
        System.out.println(result);

Output:

2.00

If no scale is provided, the preferred scale is the maximum of myValue.scale() and toAdd.scale().

If you don’t want the behavior of defaulting the scale, you can provide a MathContext object to the add() method:

        MathContext mc = new MathContext(2, RoundingMode.HALF_UP);
        BigDecimal myValue = new BigDecimal("1.5");
        BigDecimal toAdd = new BigDecimal("0.50");
        BigDecimal result = myValue.add(toAdd,mc);
        System.out.println(result);

Output:

2.0

3.2. Subtraction

Just like the addition, BigDecimal provides two methods to perform subtraction operations.
Without a MathContext

        BigDecimal myValue = new BigDecimal("1.5");
        BigDecimal toSubtract = new BigDecimal("0.50");
        BigDecimal result = myValue.subtract(toSubtract);
        System.out.println(result);

Output:

1.00

Just like the addition, if no scale is provided, the resulted scale is the maximum of myValue.scale() and toSubstract.scale().

With a MathContext

        MathContext mc = new MathContext(2, RoundingMode.HALF_UP);
        BigDecimal myValue = new BigDecimal("1.5");
        BigDecimal toSubtract = new BigDecimal("0.50");
        BigDecimal result = myValue.subtract(toSubtract,mc);
        System.out.println(result);

Output:

1.0

3.3. Multiplication

In the same way, as for addition and subtraction, multiplying two BigDecimals can be achieved in two ways: with a MathContext object and without. However, unlike addition and subtraction, if no scale is provided, the resulting scale is the sum of myValue.scale() and toMultiply.scale().

Without a MathContext

        BigDecimal myValue = new BigDecimal("1.5");
        BigDecimal toMultiply = new BigDecimal("0.50");
        BigDecimal result = myValue.multiply(toMultiply);//Summing the scale : 1 + 2 = 3
        System.out.println(result);

Output:

0.750

With a MathContext

        MathContext mc = new MathContext(2, RoundingMode.HALF_UP);
        BigDecimal myValue = new BigDecimal("1.5");
        BigDecimal toMultiply = new BigDecimal("0.50");
        BigDecimal result = myValue.multiply(toMultiply,mc);
        System.out.println(result);

Output:

0.75

3.4. Division

Similarly to the previous operators, Java provides different methods to perform BigDecimals division. However, in addition to providing a scale, you should also specify a rounding mode. Even though the RoundingMode is not required, it’s a good practice to provide it.
Just like the previous operators, Java will automatically compute the preferred scale if none is provided. The preferred scale is the difference: myValue.scale() - divisor.scale().

Without a MathContext

        BigDecimal myValue = new BigDecimal("1.500");
        BigDecimal divisor = new BigDecimal("0.5");
        BigDecimal result = myValue.divide(divisor);//Preferred scale = 3 - 1 = 2
        System.out.println(result);

Output:

3.00

With a MathContext

        MathContext mc = new MathContext(2, RoundingMode.HALF_UP);
        BigDecimal myValue = new BigDecimal("1.500");
        BigDecimal divisor = new BigDecimal("0.5");
        BigDecimal result = myValue.divide(divisor,mc);
        System.out.println(result);

Output:

3.0

4. Comparing BigDecimals

4.1. Using BigDecimal#compareTo

BigDecimal implements the Comparable interface and provides a compareTo() method to compare two BigDecimal objects.

        BigDecimal firstValue = new BigDecimal("1.5");
        BigDecimal secondValue = new BigDecimal("2.5");
        BigDecimal thirdValue = new BigDecimal("0.5");
        BigDecimal fourthValue = new BigDecimal("1.50");
        int result1 = firstValue.compareTo(secondValue);// - 1 meaning 1.5 < 2.5
        int result2 = firstValue.compareTo(thirdValue);//  1 meaning 1.5 > 0.5
        int result3 = firstValue.compareTo(fourthValue);//  0 meaning 1.5 = 1.50 regardless of the scale

4.2. Using BigDecimal#equals()

BigDecimal overrides the Object#equals() method and provides a convenient way of comparing two BigDecimals for equality.

Two BigDecimals are considered equals if and only if they have the same value and the same scale.

        BigDecimal firstValue = new BigDecimal("1.5");
        BigDecimal secondValue = new BigDecimal("1.5");
        boolean result = firstValue.equals(secondValue);//true

However:

        BigDecimal firstValue = new BigDecimal("1.5");
        BigDecimal secondValue = new BigDecimal("1.50");
        boolean result = firstValue.equals(secondValue);//false : Same value but different scales

5. Common Use Cases for BigDecimal

For most programs manipulating decimal numbers, the Double class is enough as it’ll provide better performance. However, in some specific situations, BigDecimal is the recommended class. Here are common situations:

  • High Precision Calculations: This includes financial applications where rounding errors can lead to significant inaccuracies.
  • Scientific Calculations: In this situation, it’s important to avoid issues due to floating-point arithmetic.
  • Custom Rounding Requirements: In your application, you may need to apply specific rounding behavior (nearest integer, always up, always down, etc…)

To sum up, BigDecimal is recommended when precision is more important than performance.

6. Conclusion

In this post, you learned about the BigDecimal class in Java.

Noel Kamphoa

Experienced software engineer with expertise in Telecom, Payroll, and Banking. Now Senior Software Engineer at Societe Generale Paris.