Learn Java

Java BigInteger

Using large numbers in Java

As you might remember, the standard primitive integer types cannot store very large numbers. It is not possible to assign the following large number to a variable of the type int (or even long):

int y = 62957291795228763406253098; // compilation-error: integer number too large

That is also the reason why operations with numbers can sometimes lead to type overflow. For example, check out the following code:

int a = Integer.MAX_VALUE; // 2147483647
a += 2; // -2147483647

Fortunately, the Java Class Library provides a built-in class called BigInteger for processing very large numbers (both positive and negative). The size of a stored number is only limited by the available memory.

The BigInteger class is immutable which means methods of the class return new instances instead of changing existing ones.

Although this type can store any integers, including small numbers, BigInteger should only be used if it is absolutely necessary. Using it is less intuitive compared to built-in types and, more importantly, there is always a performance hit associated with its use. BigInteger operations are substantially slower than operations on built-in integer types.

Creating objects of BigInteger

The class BigInteger belongs to the java.math package. We import it by writing the following statement:

import java.math.BigInteger;

Here is an instance of the class that stores the large number presented above:

BigInteger number = new BigInteger("62957291795228763406253098");

It is also possible to create an instance by passing a long value to the method valueOf:

BigInteger number = BigInteger.valueOf(1_000_000_000);

In addition, the class has several useful constants:

BigInteger zero = BigInteger.ZERO; // 0
BigInteger one = BigInteger.ONE;   // 1
BigInteger ten = BigInteger.TEN;   // 10

Using them is a good practice because constants allow you to reuse an already created object. This is particularly important considering that instance of BigInteger is actually quite big. Except for a memory optimization point, the code with constants is easier to read.

Compare the piece of code below:

if (something) {
    return new BigInteger("1");
}

and its analog with constants:

if (something) {
    return BigInteger.ONE;
}

Remember it and try to use built-In BigInteger constants whenever possible.

Methods of BigInteger

The class has a set of non-static methods to perform all standard arithmetic operations. The following example demonstrates the addition.

BigInteger eleven = ten.add(one);
System.out.println(eleven); // 11

System.out.println(ten); // 10, it has not changed!

Keep in mind, that the arithmetic methods do not change instances but create a new one.

Other arithmetic methods (subtraction, multiplication, integer division) are listed below:

BigInteger nine = ten.subtract(BigInteger.ONE); // 10 - 1 = 9
BigInteger oneHundredTen = ten.multiply(eleven); // 10 * 11 = 110
BigInteger twelve = oneHundredTen.divide(nine); // integer division: 12

The method negate returns a new BigInteger with the changed sign, like this:

nine.negate(); // -9

The method divideAndRemainder returns an array consisting of two numbers: the result of integer division and the remainder.

BigInteger[] pair = oneHundredTen.divideAndRemainder(nine); // 12 and 2

The class also provides methods for performing more complex math operations. The method abs returns a new BigInteger whose value is the absolute value of this BigInteger.

BigInteger number = new BigInteger("-8");
System.out.println(number.abs()); // 8

The method gcd returns the greatest common divisor of two numbers.

BigInteger three = BigInteger.valueOf(3);
BigInteger six = BigInteger.valueOf(6);
System.out.println(three.gcd(six)); // 3

The class has methods for performing bitwise and bitshift operations as well, but we do not consider them here.

Conclusion

BigInteger is a valuable class in Java for handling very large numbers that exceed the limits of primitive data types like int and long. While it offers powerful capabilities for arithmetic and advanced math operations, it's important to use it carefully due to its performance overhead. By leveraging constants and understanding its methods, you can effectively manage large integers in your Java applications.

Create a free account to access the full topic

“It has all the necessary theory, lots of practice, and projects of different levels. I haven't skipped any of the 3000+ coding exercises.”
Andrei Maftei
Hyperskill Graduate