Java - BigInteger and BigDecimal in Java

BigInteger and BigDecimal are classes in Java used when the normal primitive numeric data types such as int, long, float, and double are not suitable because of their limits or precision problems.

They are available in the java.math package:

import java.math.BigInteger;
import java.math.BigDecimal;

1. Why BigInteger and BigDecimal Are Needed

Java provides primitive data types for storing numbers:

  • int can store values up to approximately 2.1 billion.

  • long can store values up to approximately 9.22 quintillion.

  • float and double can represent decimal values, but they may introduce rounding errors.

For many ordinary calculations, these types are sufficient. However, some applications require numbers that are much larger or decimal calculations that must be extremely precise.

For example, consider:

long number = 9223372036854775807L;

This is close to the maximum value that a long can hold. If we need to work with a number larger than this, long cannot represent it.

This is where BigInteger becomes useful.

Similarly, financial applications may need exact decimal calculations. Using double for such calculations can produce unexpected results because many decimal fractions cannot be represented exactly in binary floating-point format.

BigDecimal is designed for high-precision decimal calculations.


2. BigInteger in Java

BigInteger is a class used to represent integers of arbitrary precision.

Unlike int and long, its size is not restricted to 32-bit or 64-bit integer limits. Its practical limit is mainly determined by the available memory.

For example:

import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {

        BigInteger number = new BigInteger("123456789012345678901234567890");

        System.out.println(number);
    }
}

Output:

123456789012345678901234567890

The number is much larger than the maximum value that can be stored in an int or long.


3. Creating BigInteger Objects

A BigInteger is an object, so it is created using a constructor or methods provided by the class.

The most common approach is:

BigInteger number = new BigInteger("12345678901234567890");

The number is generally supplied as a String.

This is important because writing:

BigInteger number = new BigInteger(12345678901234567890);

will not work because the literal itself is too large for Java's ordinary integer types.

Instead, write:

BigInteger number = new BigInteger("12345678901234567890");

4. BigInteger Arithmetic

Since BigInteger is an object rather than a primitive data type, normal arithmetic operators such as +, -, *, and / cannot be directly used with it.

For example, this is invalid:

BigInteger a = new BigInteger("100");
BigInteger b = new BigInteger("50");

BigInteger c = a + b;

Instead, Java provides methods for arithmetic operations.

Addition

Use add():

BigInteger a = new BigInteger("100");
BigInteger b = new BigInteger("50");

BigInteger result = a.add(b);

System.out.println(result);

Output:

150

Subtraction

Use subtract():

BigInteger result = a.subtract(b);

Multiplication

Use multiply():

BigInteger result = a.multiply(b);

Division

Use divide():

BigInteger result = a.divide(b);

Remainder

Use remainder():

BigInteger result = a.remainder(b);

For example:

BigInteger a = new BigInteger("17");
BigInteger b = new BigInteger("5");

System.out.println(a.divide(b));
System.out.println(a.remainder(b));

Output:

3
2

5. BigInteger Comparison

Relational operators such as > and < cannot be directly used with BigInteger objects.

Instead, use the compareTo() method.

BigInteger a = new BigInteger("100");
BigInteger b = new BigInteger("200");

int result = a.compareTo(b);

System.out.println(result);

compareTo() returns:

  • A negative value if the first number is smaller.

  • 0 if both numbers are equal.

  • A positive value if the first number is larger.

For example:

if (a.compareTo(b) < 0) {
    System.out.println("a is smaller");
}

6. Useful BigInteger Methods

Some commonly used methods include:

Method Purpose
add() Adds two BigInteger values
subtract() Subtracts one value from another
multiply() Multiplies two values
divide() Performs integer division
remainder() Returns the remainder
pow() Calculates a power
abs() Returns the absolute value
negate() Changes the sign
compareTo() Compares two BigInteger values
gcd() Finds the greatest common divisor
mod() Calculates the mathematical modulus

For example:

BigInteger number = new BigInteger("5");

System.out.println(number.pow(3));

Output:

125

7. BigInteger Example: Factorial

BigInteger is particularly useful for factorial calculations because factorial values become extremely large.

For example:

5! = 120
10! = 3628800
20! = 2432902008176640000

For even larger values, long eventually becomes insufficient.

Example:

import java.math.BigInteger;

public class Main {
    public static void main(String[] args) {

        BigInteger factorial = BigInteger.ONE;

        for (int i = 1; i <= 50; i++) {
            factorial = factorial.multiply(BigInteger.valueOf(i));
        }

        System.out.println(factorial);
    }
}

Here, BigInteger allows the program to calculate 50! without overflowing a long.


8. BigDecimal in Java

BigDecimal is used for high-precision decimal arithmetic.

It is especially useful when accuracy is important, such as in:

  • Banking applications

  • Financial calculations

  • Accounting software

  • Tax calculations

  • Scientific calculations

  • Currency-related applications

Example:

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {

        BigDecimal price = new BigDecimal("199.99");

        System.out.println(price);
    }
}

Output:

199.99

9. Why BigDecimal Is Preferred for Financial Calculations

Consider this example using double:

double a = 0.1;
double b = 0.2;

System.out.println(a + b);

You might expect:

0.3

But the result can be:

0.30000000000000004

This happens because floating-point numbers such as double use binary representation, and some decimal fractions cannot be represented exactly.

With BigDecimal, we can perform decimal calculations more accurately:

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");

BigDecimal result = a.add(b);

System.out.println(result);

Output:

0.3

This is one of the major reasons BigDecimal is commonly used for monetary calculations.


10. Creating BigDecimal Correctly

When exact decimal values are required, it is generally preferable to create BigDecimal from a String.

Recommended:

BigDecimal value = new BigDecimal("0.1");

Using a double can preserve the approximation already present in the double value:

BigDecimal value = new BigDecimal(0.1);

For exact decimal intent, use:

BigDecimal value = BigDecimal.valueOf(0.1);

or, especially when the value is written as a literal decimal:

BigDecimal value = new BigDecimal("0.1");

11. BigDecimal Arithmetic

Like BigInteger, BigDecimal uses methods instead of arithmetic operators.

Addition

BigDecimal a = new BigDecimal("10.50");
BigDecimal b = new BigDecimal("5.25");

BigDecimal result = a.add(b);

System.out.println(result);

Output:

15.75

Subtraction

BigDecimal result = a.subtract(b);

Multiplication

BigDecimal result = a.multiply(b);

Division

Division requires special consideration because the decimal result may not terminate.

For example:

BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");

BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);

System.out.println(result);

Output:

3.33

Here, the program specifies:

  • 2 decimal places

  • RoundingMode.HALF_UP as the rounding method

The required import is:

import java.math.RoundingMode;

12. Rounding with BigDecimal

Rounding is an important part of BigDecimal, especially for financial applications.

For example:

BigDecimal value = new BigDecimal("25.6789");

BigDecimal result = value.setScale(2, RoundingMode.HALF_UP);

System.out.println(result);

Output:

25.68

setScale() specifies the number of digits after the decimal point.

Common rounding modes include:

  • RoundingMode.UP

  • RoundingMode.DOWN

  • RoundingMode.CEILING

  • RoundingMode.FLOOR

  • RoundingMode.HALF_UP

  • RoundingMode.HALF_DOWN

  • RoundingMode.HALF_EVEN

The appropriate rounding method depends on the requirements of the application.


13. Comparing BigDecimal Values

Avoid using == when comparing the numerical values of BigDecimal objects.

Instead, use compareTo() when you want numerical comparison.

BigDecimal a = new BigDecimal("10.0");
BigDecimal b = new BigDecimal("10.00");

if (a.compareTo(b) == 0) {
    System.out.println("Both values are numerically equal");
}

Output:

Both values are numerically equal

This is important because BigDecimal can retain scale information. For example, 10.0 and 10.00 have different scales even though they represent the same numerical value.


14. BigInteger vs BigDecimal

The main difference is that BigInteger is designed for whole numbers, while BigDecimal is designed for decimal numbers with arbitrary precision.

Feature BigInteger BigDecimal
Package java.math java.math
Handles Whole numbers Decimal numbers
Decimal values No Yes
Arbitrary precision Yes Yes
Common use Very large integers Precise decimal calculations
Financial calculations Sometimes Very common
Arithmetic operators Not directly supported Not directly supported
Uses methods Yes Yes

For example:

BigInteger population = new BigInteger("98765432109876543210");

is appropriate for a very large whole number.

Whereas:

BigDecimal salary = new BigDecimal("9876543210.75");

is appropriate when an exact decimal value is required.


15. Important Characteristics

Both BigInteger and BigDecimal are immutable.

This means that when an operation is performed, the existing object is not modified. Instead, a new object is returned.

For example:

BigInteger a = new BigInteger("100");
BigInteger b = a.add(BigInteger.TEN);

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

Output:

100
110

The original a remains unchanged.

The same principle applies to BigDecimal.

BigDecimal price = new BigDecimal("100.00");

price.add(new BigDecimal("20.00"));

System.out.println(price);

Output:

100.00

The result of add() was not stored.

The correct approach is:

price = price.add(new BigDecimal("20.00"));

Now price refers to the new value.


16. Advantages

The major advantages of BigInteger and BigDecimal are:

BigInteger

It can handle integers much larger than the limits of int and long.

It is useful for mathematical problems involving extremely large numbers.

It provides methods for arithmetic, comparison, powers, GCD calculations, and modular operations.

BigDecimal

It provides high-precision decimal arithmetic.

It is suitable for applications where numerical accuracy is important.

It allows developers to control decimal scale and rounding.

It is widely appropriate for monetary and financial calculations.


17. Limitations

Although these classes are powerful, they have some disadvantages.

First, they are objects rather than primitive values, so they generally require more memory than primitive numeric types.

Second, operations can be slower than operations on primitive types.

Third, developers must use methods such as add(), subtract(), and multiply() instead of familiar operators.

For these reasons, BigInteger and BigDecimal should be used when their additional precision or range is actually needed.


18. Complete Example

The following program demonstrates both classes:

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

public class Main {
    public static void main(String[] args) {

        BigInteger largeNumber =
            new BigInteger("123456789012345678901234567890");

        BigInteger anotherNumber =
            new BigInteger("98765432109876543210");

        BigInteger integerResult =
            largeNumber.add(anotherNumber);

        System.out.println("BigInteger Addition: " + integerResult);


        BigDecimal price =
            new BigDecimal("199.99");

        BigDecimal quantity =
            new BigDecimal("3");

        BigDecimal total =
            price.multiply(quantity);

        System.out.println("Total Price: " + total);


        BigDecimal division =
            new BigDecimal("10")
                .divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP);

        System.out.println("Division: " + division);
    }
}

Possible output:

BigInteger Addition: 123456789111111111012345678900
Total Price: 599.97
Division: 3.33

Conclusion

BigInteger and BigDecimal extend Java's numerical capabilities beyond the limitations of primitive numeric types. BigInteger should be used when calculations involve extremely large whole numbers, while BigDecimal should be used when calculations require highly precise decimal values.

For example, a program calculating a very large factorial can use BigInteger, while a banking application calculating account balances, interest, or transaction amounts can use BigDecimal. Their arbitrary precision, immutable design, and specialized arithmetic methods make them important classes for applications where ordinary numeric types are not sufficiently reliable or large enough.