BigInteger
java.math.BigInteger represents integers of arbitrary size. Where long stops at about 9.2 × 10¹⁸, a BigInteger can hold a number with thousands or millions of digits, limited only by memory. It never overflows: every operation produces the exact mathematical result. BigInteger is used in cryptography, combinatorics, number theory, very large identifiers and counters, and any calculation whose intermediate values exceed 64 bits.
Why long Is Not Always Enough
long f20 = 2_432_902_008_176_640_000L; // 20! fits in a long
long f21 = f20 * 21; // overflow: -4249290049419214848
Multiplying past Long.MAX_VALUE silently wraps around to a negative number. Math.multiplyExact would at least throw an exception, but it cannot produce the correct value. BigInteger can:
BigInteger f21 = BigInteger.valueOf(2_432_902_008_176_640_000L).multiply(BigInteger.valueOf(21));
System.out.println(f21); // 51090942171709440000
Creating BigIntegers
BigInteger a = BigInteger.valueOf(42); // from a long
BigInteger b = new BigInteger("123456789012345678901234567890"); // from decimal text
BigInteger c = new BigInteger("ff", 16); // from text in base 16 → 255
BigInteger d = BigInteger.ONE; // constants: ZERO, ONE, TWO, TEN
- Use
valueOffor values that fit in along; it may return cached instances. - Use the
Stringconstructor for larger values. Invalid text throwsNumberFormatException.
Operations Are Methods, and Results Are New Objects
BigInteger is an object, so the arithmetic operators do not work on it. Each operation is a method that returns a new BigInteger; the original is immutable and never changes:
BigInteger x = BigInteger.ONE;
x.add(BigInteger.TEN); // result discarded: x is still 1
x = x.add(BigInteger.TEN); // correct: x is now 11
Forgetting to use the return value is the most common BigInteger mistake, exactly as with String.
Arithmetic
| Operation | Method | Example (a = 17, b = 5) |
|---|---|---|
| Addition | a.add(b) | 22 |
| Subtraction | a.subtract(b) | 12 |
| Multiplication | a.multiply(b) | 85 |
| Division | a.divide(b) | 3 (truncated toward zero) |
| Remainder | a.remainder(b) | 2 (sign follows a) |
| Modulus | a.mod(b) | 2 (always non-negative; b must be positive) |
| Quotient and remainder | a.divideAndRemainder(b) | [3, 2] |
| Power | a.pow(3) | 4913 |
| Negation, absolute value | a.negate(), a.abs() | −17, 17 |
| Integer square root | a.sqrt() | 4 (Java 9+) |
Division by zero throws ArithmeticException.
Operations chain naturally:
BigInteger result = a.multiply(a).add(b).mod(BigInteger.valueOf(1_000_000_007));
Number theory
| Method | Purpose |
|---|---|
gcd(b) | Greatest common divisor |
modPow(exp, m) | (this^exp) mod m, computed efficiently even for huge exponents |
modInverse(m) | Multiplicative inverse modulo m |
isProbablePrime(certainty) | Primality test (probability of error at most 2^−certainty) |
nextProbablePrime() | Next probable prime greater than this value |
BigInteger.valueOf(48).gcd(BigInteger.valueOf(180)); // 12
BigInteger.valueOf(7).modPow(BigInteger.valueOf(128), BigInteger.valueOf(13)); // 3
BigInteger.valueOf(97).isProbablePrime(20); // true
BigInteger.valueOf(100).nextProbablePrime(); // 101
modPow and modInverse are the core operations of public-key cryptography such as RSA. (Real cryptographic code should use the java.security and javax.crypto APIs rather than hand-built algorithms.)
Bit operations
BigInteger supports and, or, xor, not, shiftLeft, shiftRight, testBit, setBit, clearBit, bitLength, and bitCount, treating the value as an infinitely sign-extended two's-complement number. bitLength() is a convenient way to check how many bits a value needs.
Comparing
BigInteger has no < or >; use compareTo, and use equals for equality:
BigInteger a = new BigInteger("10");
a.compareTo(BigInteger.ONE) > 0; // true: a > 1
a.equals(BigInteger.TEN); // true
a == BigInteger.TEN; // false: different objects
a.signum(); // 1 (also -1 or 0)
a.max(BigInteger.TWO); // 10
BigInteger implements Comparable, so it can be sorted and used as a TreeMap key, and it implements equals/hashCode correctly for HashMap.
Converting Back to Primitives and Text
BigInteger big = new BigInteger("51090942171709440000");
big.toString(); // "51090942171709440000"
big.toString(16); // hexadecimal text
big.longValue(); // -4249290049419214848: silently keeps only the low 64 bits
big.longValueExact(); // ArithmeticException: BigInteger out of long range
big.doubleValue(); // 5.109094217170944E19 (approximate)
intValue() and longValue() truncate silently, just like narrowing casts. Use intValueExact() and longValueExact() when a value is expected to fit and a wrong result would be worse than an exception.
Performance
BigInteger arithmetic runs in software, on arrays of 32-bit words, and allocates a new object for every result. It is much slower than long arithmetic: fine for exact computations on occasional large numbers, wasteful for ordinary counters and loops. Use long when values fit (and Math.*Exact methods to detect overflow), and switch to BigInteger only where the range is genuinely needed.
Practical Example: Factorials and Combinations
Counting arrangements, lottery odds, and probability calculations quickly produce numbers far beyond long.
import java.math.BigInteger;
public class BigI {
static BigInteger factorial(int n) {
BigInteger result = BigInteger.ONE;
for (int i = 2; i <= n; i++) result = result.multiply(BigInteger.valueOf(i));
return result;
}
static BigInteger choose(int n, int k) {
BigInteger r = BigInteger.ONE;
for (int i = 1; i <= k; i++) {
r = r.multiply(BigInteger.valueOf(n - k + i)).divide(BigInteger.valueOf(i));
}
return r;
}
public static void main(String[] args) {
System.out.println("20! = " + factorial(20) + " (fits in long: " + (factorial(20).bitLength() < 64) + ")");
System.out.println("21! = " + factorial(21) + " (fits in long: " + (factorial(21).bitLength() < 64) + ")");
System.out.println("50! has " + factorial(50).toString().length() + " digits");
System.out.println("C(100, 50) = " + choose(100, 50));
try {
System.out.println(factorial(21).longValueExact());
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
}
}
}
Output:
20! = 2432902008176640000 (fits in long: true)
21! = 51090942171709440000 (fits in long: false)
50! has 65 digits
C(100, 50) = 100891344545564193334812497256
BigInteger out of long range
Each step reassigns result = result.multiply(...), because multiply returns a new object. bitLength() < 64 checks whether a value would fit in a signed long: 20! needs 62 bits and fits, while 21! needs 66. choose computes combinations without calculating the full factorials. Multiplying before dividing at each step keeps every intermediate value a whole number, since the running product after step i is itself a binomial coefficient, so the division is always exact. C(100, 50), the number of ways to choose 50 items from 100, has 30 digits; no primitive type could hold it. Finally, longValueExact refuses to convert 21! to a long instead of silently returning a wrong negative number.