This article introduces multiplicative inverses modulo an integer and discusses common methods for finding them.
Basic concepts
The multiplicative inverse of a nonzero real number is its reciprocal . Similarly, in number theory, the inverse of an integer modulo can be defined as , or simply . This is the modular multiplicative inverse, also called the number-theoretic reciprocal.
Inverse
For nonzero integers , if there exists a such that , then is called the inverse of modulo .
This is equivalent to saying that is a solution of the linear congruence . By the properties of linear congruences, the inverse exists if and only if , that is, if are coprime; it is also unique modulo .
Finding a single inverse
The inverse of a single integer can be found in time using the extended Euclidean algorithm or binary exponentiation.
Extended Euclidean algorithm
Finding an inverse is equivalent to solving a linear congruence. Therefore, the extended Euclidean algorithm can find the inverse in time. Since the corresponding linear equation is special, the relevant steps can be simplified appropriately.
Reference implementation
C++
// Extended Euclidean algorithm.
void ex_gcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1;
y = 0;
} else {
ex_gcd(b, a % b, y, x);
y -= a / b * x;
}
}
// Returns the modular inverse of a modulo m.
// Assumes that gcd(a, m) = 1, so the inverse exists.
int inverse(int a, int m) {
int x, y;
ex_gcd(a, m, x, y);
return (x % m + m) % m;
}
Python
# Extended Euclidean algorithm.
def ex_gcd(a, b):
if b == 0:
return 1, 0
else:
x1, y1 = ex_gcd(b, a % b)
x = y1
y = x1 - (a // b) * y1
return x, y
# Returns the modular inverse of a modulo m.
# Assumes that gcd(a, m) = 1, so the inverse exists.
def inverse(a, m):
x, y = ex_gcd(a, m)
return (x % m + m) % m
This algorithm applies whenever the inverse exists.
Binary exponentiation
This method mainly applies when the modulus is a prime . By Fermat's little theorem, for every ,
By the uniqueness of the inverse, equals . Therefore, binary exponentiation can calculate it in time:
Reference implementation
C++
// Binary exponentiation.
int pow(int a, int b, int m) {
long long res = 1, po = a;
for (; b; b >>= 1) {
if (b & 1) res = res * po % m;
po = po * po % m;
}
return res;
}
// Returns the modular inverse of a prime modulo p.
int inverse(int a, int p) { return pow(a, p - 2, p); }
Python
# Returns the modular inverse of a prime modulo p.
# Use built-in pow function.
def inverse(a, p):
return pow(a, p - 2, p)
In theory, this method can be extended to a general modulus using Euler's theorem, calculating the inverse with . However, finding the Euler totient function for a single value is not easy, so this algorithm is inefficient in general.
Finding multiple inverses
In some situations, the inverses modulo of many integers must be computed quickly. Solving them one by one takes time in total. In fact, processing them together allows all inverses to be found in time.
Consider the prefix products of the sequence :
As long as every is coprime to , their product is also coprime to . Therefore, the algorithm described above can find . Since the inverse of a product is the product of the inverses, traversing the sequence backwards from gives the inverse of every :
The inverse of an individual can then be calculated by
A reference implementation follows:
Reference implementation
C++
// Returns the modular inverses for each x in a modulo m.
// Assume x mod m exists for each x in a.
std::vector<int> batch_inverse(const std::vector<int>& a, int m) {
int n = a.size();
std::vector<int> prod(n);
long long s = 1;
for (int i = 0; i < n; ++i) {
// prod[i] = product of a[0...i-1]; prod[0] = 1.
prod[i] = s;
s = s * a[i] % m;
}
// s = product of all elements in a.
s = inverse(s, m);
std::vector<int> res(n);
for (int i = n - 1; i >= 0; --i) {
res[i] = s * prod[i] % m;
s = s * a[i] % m;
}
return res;
}
Python
# Returns the modular inverses for each x in a modulo m.
# Assume x mod m exists for each x in a.
def batch_inverse(a, m):
n = len(a)
prod = [0] * n
s = 1
for i in range(n):
# prod[i] = product of a[0...i-1]; prod[0] = 1.
prod[i] = s
s = s * a[i] % m
# s = product of all elements in a.
s = inverse(s, m)
res = [0] * n
for i in reversed(range(n)):
res[i] = s * prod[i] % m
s = s * a[i] % m
return res
The algorithm computes only one inverse of an individual element, so its total time complexity is .
Linear-time preprocessing of inverses
If the inverses modulo a prime of the first positive integers are needed, the recurrence discussed in this section can calculate them in time. This method is often used to preprocess the reciprocals of the first positive integers' factorials when calculating binomial coefficients.
For a positive integer with , consider Euclidean division:
Taking this equation modulo the prime gives
Multiplying both sides by gives
This is the formula for computing inverses by a linear-time recurrence. Since , it reduces the problem of finding to the smaller problem . Therefore, starting from and applying the formula successively for each yields the inverses of the first integers in time.
A reference implementation follows:
Reference implementation
C++
// Precomputes modular inverses of all integers from 1 to n modulo prime p.
std::vector<int> precompute_inverses(int n, int p) {
std::vector<int> res(n + 1);
res[1] = 1;
for (int i = 2; i <= n; ++i) {
res[i] = (long long)(p - p / i) * res[p % i] % p;
}
return res;
}
Python
# Precomputes modular inverses of all integers from 1 to n modulo prime p.
def precompute_inverses(n, p):
res = [0] * (n + 1)
res[1] = 1
for i in range(2, n + 1):
res[i] = (p - p // i) * res[p % i] % p
return res
This algorithm applies only when the modulus is prime. For a non-prime modulus , the obtained in the recurrence is not guaranteed to be coprime to , so the required by the recurrence may not exist. For example, let . Then , which has no inverse modulo .
After obtaining this recurrence, a natural idea is to recursively find the inverse of any number . At each recursive call, use the recurrence to reduce it to the inverse of the smaller remainder , stopping when the remainder becomes . The complexity of this approach is not currently clear1, so the conventional method described above is recommended.
Exercises
- LOJ 110 Modular Multiplicative Inverse
- LOJ 161 Modular Multiplicative Inverse 2
- LOJ 2605「NOIP2012」Congruence Equation
- Luogu P2054「AHOI2005」Shuffle
- LOJ 2034「SDOI2016」Permutation Counting
References and notes
Footnotes
-
An answer by riteme on Zhihu points out that the theoretically known upper bound for the complexity is , while its performance on actual random data is close to . ↩