Representing very large integers

When solving algorithm problems, input/output ranges are often split into Small Input and Large Input. Most cases are handled by Java primitive types, but not all.

For example, int represents integers only in range \({ -2 }^{ 31 }\) ~ \({ 2 }^{ 31 } - 1\). long supports larger values, but still has an upper bound of \({ -2 }^{ 63 }-1\).

long is already very large for typical applications. But if you need near-unbounded integer size, use BigInteger.


Declaration

BigInteger is in java.math. As stated in Javadoc, it represents immutable arbitrary-precision integers. Instances are usually created from strings, and several constructors/static factory methods are available.

// hexadecimal
BigInteger bigIntWithRadix = new BigInteger("64", 16);

// from integer value
BigInteger bigIntWithValue = BigInteger.valueOf(100);

// from string
BigInteger bigIntWithString = new BigInteger("100");


Arithmetic operations

Add

Use add for addition between BigInteger instances. BigInteger.TEN used below is a globally accessible constant. Other constants include ONE, NEGATIVE_ONE, and TWO (from Java 9).

BigInteger value = new BigInteger("10");

// 20
BigInteger result = value.add(BigInteger.TEN);

Subtract

Use subtract.

BigInteger value = BigInteger.TEN;

// 8
BigInteger result = value.subtract(BigInteger.TWO);

Multiply

Use multiply.

BigInteger value = BigInteger.valueOf(3);

// 6
BigInteger result = value.multiply(BigInteger.TWO);

Divide

Use divide for division between BigInteger instances.

BigInteger value = BigInteger.TEN;
	
// 5
BigInteger result = value.divide(BigInteger.TWO);


Bit operations

Because BigInteger handles large immutable values, performance is generally lower than long. To compensate, several bit-level operation methods are provided.

bitLength

bitLength returns the number of bits required to represent this BigInteger value in binary.

BigInteger value = BigInteger.TEN;

// 4
value.bitCount()


// for reference, convert to binary as below
// result: 1010    
value.toString(2);

testBit

testBit checks whether a bit at a given position is 1 or 0. It takes an integer index and checks the (n+1)-th bit from the right in binary representation.

BigInteger value = BigInteger.TEN;

// false
value.testBit(0);

Shift operations (shiftLeft, shiftRight)

You can also do bit shifts as below. To verify shifted bits, the example prints binary by setting radix parameter to 2 in toString.

BigInteger value = BigInteger.TEN;

// value: 1010
value.toString(2)

// shiftLeft: 10100
value.shiftLeft(1).toString(2)

// shiftRight: 101
value.shiftRight(1).toString(2)

Other methods

Remainder

Use remainder to get modulo result.

BigInteger value = new BigInteger("3");

// 1
value.remainder(BigInteger.TWO);

Compare values

Use compareTo to compare BigInteger instances. It returns 1 if greater than parameter, 0 if equal, and -1 if smaller.

BigInteger value = BigInteger.TEN;

// 1
value.compareTo(BigInteger.TWO);

// 0
value.compareTo(BigInteger.TEN);

// -1
BigInteger.TWO.compareTo(value);

Max and min

Use max and min to get larger/smaller value compared with parameter.

BigInteger value = BigInteger.TEN;

// 10
value.max(BigInteger.TWO);

// 2 
value.min(BigInteger.TWO);