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:
-
intcan store values up to approximately 2.1 billion. -
longcan store values up to approximately 9.22 quintillion. -
floatanddoublecan 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.
-
0if 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:
-
2decimal places -
RoundingMode.HALF_UPas 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.