Number Theory & Algebra contents
Modular Multiplicative Inverse
Divide under a modulus. Find a^-1 mod m with extended Euclid, with Fermat/Euler, with Python's pow, and for a whole array at once.
Read first: Extended Euclidean Algorithm, Euler's Totient Function
Addition, subtraction and multiplication work modulo by simply reducing the result. Division does not: you cannot divide the remainders. Instead you multiply by an inverse.
Definition
The modular multiplicative inverse of modulo is a number such that
and it is written . Then "" means .
When does it exist? Exactly when (the numbers are coprime). If a common factor existed, would always be a multiple of modulo and could never be . When it exists it is unique modulo . For a prime every has an inverse.
Example: , so .
Method 1: extended Euclid
means for some integer . The extended Euclidean algorithm solves this directly. It works for any modulus (not only primes) and costs :
def extended_gcd(a, b):
if b == 0:
return a, 1, 0
g, x1, y1 = extended_gcd(b, a % b)
return g, y1, x1 - (a // b) * y1
def inverse_euclid(a, m):
g, x, _ = extended_gcd(a % m, m)
if g != 1:
raise ValueError(f"{a} has no inverse modulo {m}")
return x % m # normalize into [0, m)
assert inverse_euclid(3, 7) == 5
assert inverse_euclid(10, 17) == 12
assert all(a * inverse_euclid(a, 101) % 101 == 1 for a in range(1, 101))Method 2: binary exponentiation (Fermat / Euler)
By Euler's theorem, if then , hence
and for a prime (Fermat's little theorem) simply . Computing the power takes with binary exponentiation:
MOD = 1_000_000_007
def inverse_fermat(a, p=MOD):
return pow(a, p - 2, p)
assert inverse_fermat(3, 7) == 5
assert inverse_fermat(2) * 2 % MOD == 1
assert all(inverse_fermat(a, 101) == inverse_euclid(a, 101) for a in range(1, 101))This is the go-to one-liner in contests where the modulus is or .
Method 3: Python's built-in
Since Python 3.8, the three-argument pow accepts a negative exponent and computes the modular inverse (raising ValueError if none exists):
assert pow(3, -1, 7) == 5
assert pow(10, -1, 17) == 12
assert pow(7, -2, 100) == pow(pow(7, -1, 100), 2, 100)
try:
pow(6, -1, 9) # gcd(6, 9) = 3
except ValueError:
pass
else:
raise AssertionError("expected ValueError")Use it: it is the shortest, works for any coprime modulus, and runs in C.
Method 4: all inverses modulo a prime in
Let be prime and write with and . Then . Multiply by :
and has already been computed:
def inverses_upto(n, p=MOD):
inv = [0, 1] + [0] * (n - 1)
for i in range(2, n + 1):
inv[i] = (p - (p // i) * inv[p % i] % p) % p
return inv
inv = inverses_upto(1000)
assert all(i * inv[i] % MOD == 1 for i in range(1, 1001))This is how you precompute factorial inverses for binomial coefficients.
Method 5: inverses of an arbitrary array
Inverting numbers separately costs . With prefix products you need just one inversion:
- Compute prefix products .
- Invert the total once.
- Walk backwards. If
runningholds , then , and multiplyingrunningby gives for the next step.
def batch_inverse(a, m=MOD):
n = len(a)
prefix = [1] * (n + 1)
for i, x in enumerate(a):
prefix[i + 1] = prefix[i] * x % m
running = pow(prefix[n], -1, m) # (a_1 ... a_n)^-1
result = [0] * n
for i in range(n - 1, -1, -1):
result[i] = prefix[i] * running % m
running = running * a[i] % m # drop a_i: running is now (a_1 ... a_{i-1})^-1
return result
nums = [3, 5, 7, 123456789, 999999999]
assert batch_inverse(nums) == [pow(x, -1, MOD) for x in nums]Which method?
| You need | Use |
|---|---|
| one inverse, any modulus | pow(a, -1, m) |
| one inverse, contest template | pow(a, m - 2, m) for prime |
| linear recurrence | |
| inverses of an arbitrary list | prefix-product trick |