ZetCode

Java BigDecimal

last modified July 7, 2020

Java BigDecimal tutorial shows how to perform exact calculations in Java with BigDecimal.

BigDecimal

BigDecimal represents an immutable, arbitrary-precision signed decimal number. It is used for high-precision arithmetic. BigDecimal provides operations for arithmetic, scale manipulation, rounding, comparison, hashing, and format conversion.

BigDecimal consists of two parts:

For instance, BigDecimal 2.18 has the unscaled value of 218 and the scale of 2.

BigDecimal is used in areas where high-precision is necessary; for instance, financial transactions or engineering calculations. The arithmetic operations of BigDecimal values are done with methods such as add or subtract; the +, -, *, \ operators are not overloaded.

Java BigDecimal basic arithmetic operations

The following example shows basic arithmetic operations with BigDecimal.

com/zetcode/BigDecimalEx.java
package com.zetcode;

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

public class BigDecimalEx {

    public static void main(String[] args) {

        BigDecimal val1 = new BigDecimal("3.44");
        BigDecimal val2 = new BigDecimal("2.74");

        BigDecimal res1 = val1.add(val2);
        System.out.println(res1);

        BigDecimal res2 = val1.subtract(val2);
        System.out.println(res2);

        BigDecimal res3 = val1.multiply(val2);
        System.out.println(res3);

        BigDecimal res4 = val1.divide(BigDecimal.TEN, RoundingMode.DOWN);
        System.out.println(res4);

        BigDecimal res5 = val1.divide(val2, 15, RoundingMode.HALF_UP);
        System.out.println(res5);
    }
}

In the example, we have addition, subtraction, multiplication, and division operations.

BigDecimal val1 = new BigDecimal("3.44");
BigDecimal val2 = new BigDecimal("2.74");

We create two BigDecimal values. The numbers are passed as strings.

BigDecimal res1 = val1.add(val2);
System.out.println(res1);

Here we add two BigDecimal numbers. The addition operation is performed with the add method.

BigDecimal res4 = val1.divide(BigDecimal.TEN, RoundingMode.DOWN);
System.out.println(res4);

When doing the division operation, we also need to specify the rounding mode.

6.18
0.70
9.4256
0.34
1.255474452554745

This is the output.

Java BigDecimal precision

BigDecimal is used for high-precision arithmetic.

com/zetcode/BigDecimalEx2.java
package com.zetcode;

import java.math.BigDecimal;

public class BigDecimalEx2 {

    public static void main(String[] args) {

        double a = 0.1 + 0.1 + 0.1;
        double b = 0.3;

        System.out.println(a);
        System.out.println(b);
        System.out.println(a == b);

        BigDecimal c = new BigDecimal("0.1").add(new BigDecimal("0.1"))
                .add(new BigDecimal("0.1"));
        BigDecimal d = new BigDecimal("0.3");

        System.out.println(c);
        System.out.println(d);
        System.out.println(c.equals(d));
    }
}

In the example, we compare the precision of a double type with BigDecimal. We add three floating point values and compare it with the expected output.

0.30000000000000004
0.3
false
0.3
0.3
true

There is a small margin error for double; therefore, the operation is not precise. The BigDecimal gives the expected output.

Java BigDecimal rounding mode

The BigDecimal class gives its user complete control over rounding behavior. If no rounding mode is specified and the exact result cannot be represented, an exception is thrown.

com/zetcode/BigDecimalEx3.java
package com.zetcode;

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

public class BigDecimalEx3 {

    public static void main(String[] args) {

        BigDecimal x = new BigDecimal("5.54");
        BigDecimal x2 = x.setScale(1, RoundingMode.FLOOR);
        System.out.println(x2);

        BigDecimal y = new BigDecimal("5.94");
        BigDecimal y2 = y.setScale(1, RoundingMode.CEILING);
        System.out.println(y2);
    }
}

In the example, we round two values in two different rounding modes.

BigDecimal x = new BigDecimal("5.54");
BigDecimal x2 = x.setScale(1, RoundingMode.FLOOR);

With the setScale method, we provide the scale and the rounding mode. In our case, we round the value to one decimal place with a rounding mode RoundingMode.FLOOR, which rouds towards negative infinity.

5.5
6.0

This is the output.

Java BigDecimal comparison

With the compareTo method, two BigDecimal objects that are equal in value but have a different scale (like 4.0 and 4.00) are considered equal by this method.

com/zetcode/BigDecimalEx4.java
package com.zetcode;

import java.math.BigDecimal;

public class BigDecimalEx4 {

    public static void main(String[] args) {

        BigDecimal x = new BigDecimal("1.6");
        BigDecimal y = new BigDecimal("1.60");

        System.out.println(x.equals(y));
        System.out.println(x.compareTo(y));

    }
}

The example compares values 1.6 and 1.60 with equals and compareTo.

false
0

The compareTo returns 0 for values that are equal.

Java BigDecimal practical example

The following example groups produts by category and calculates the total price of all products in the categories.

com/zetcode/Product.java
package com.zetcode;

import java.math.BigDecimal;

public class Product {

    private String name;
    private String category;
    private BigDecimal price;

    public Product(String name, String category, BigDecimal price) {

        this.name = name;
        this.category = category;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    @Override
    public String toString() {

        var sb = new StringBuilder("Product{");
        sb.append("name='").append(name).append('\'');
        sb.append(", category='").append(category).append('\'');
        sb.append(", price=").append(price);
        sb.append('}');
        return sb.toString();
    }
}

This is a Product class. It has a price of BigDecimal.

com/zetcode/BigDecimalEx5.java
package com.zetcode;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class BigDecimalEx5 {

    public static void main(String[] args) {

        Map<String, Map<BigDecimal, List<Product>>> productsByCategories =
                products().stream().collect(
                        Collectors.groupingBy(Product::getCategory,
                                Collectors.groupingBy(Product::getPrice)));

        productsByCategories.forEach((k, v) -> {

            System.out.printf("%s: ", k);

            BigDecimal sum = new BigDecimal("0");

            var prices = v.keySet();
            for (var price: prices) {

                sum = sum.add(price);
            }

            System.out.println(sum);
        });
    }

    private static List<Product> products() {

        return List.of(
                new Product("apple", "fruit", new BigDecimal("4.50")),
                new Product("banana", "fruit", new BigDecimal("3.76")),
                new Product("carrot", "vegetables", new BigDecimal("2.98")),
                new Product("potato", "vegetables", new BigDecimal("0.92")),
                new Product("garlic", "vegetables", new BigDecimal("1.32")),
                new Product("ginger", "vegetables", new BigDecimal("2.45")),
                new Product("white bread", "bakery", new BigDecimal("1.50")),
                new Product("roll", "bakery", new BigDecimal("0.08")),
                new Product("bagel", "bakery", new BigDecimal("0.15"))
        );
    }
}

We have various groceries in three categories: fruit, vegetables, and bakery. Our goal is to group the produts by their categories and calculate the sum of all prices in the respective categories.

Map<String, Map<BigDecimal, List<Product>>> productsByCategories =
products().stream().collect(
        Collectors.groupingBy(Product::getCategory,
                Collectors.groupingBy(Product::getPrice)));

Using Java streams, we group the products by their categories and then prices.

productsByCategories.forEach((k, v) -> {

    System.out.printf("%s: ", k);

    BigDecimal sum = new BigDecimal("0");

    var prices = v.keySet();
    for (var price: prices) {

        sum = sum.add(price);
    }

    System.out.println(sum);
});

In the forEach loop, we calculate the sum of all prices for each category.

bakery: 1.73
fruit: 8.26
vegetables: 7.67

This is the output.

In this tutorial, we have shown how to do high-precision arithmetic operations in Java with BigDecimal.

List all Java tutorials.