Modular Multiplicative Inverse

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 a∈Ra\in\mathbf R is its reciprocal a−1a^{-1}. Similarly, in number theory, the inverse of an integer aa modulo mm can be defined as a−1 mod ma^{-1}\bmod m, or simply a−1a^{-1}. This is the modular multiplicative inverse, also called the number-theoretic reciprocal.

Inverse

For nonzero integers a,ma,m, if there exists a bb such that ab≡1(modm)ab\equiv 1\pmod m, then bb is called the inverse of aa modulo mm.

This is equivalent to saying that bb is a solution of the linear congruence ax≡1(modm)ax\equiv 1\pmod m. By the properties of linear congruences, the inverse a−1 mod ma^{-1}\bmod m exists if and only if gcd⁡(a,m)=1\gcd(a,m)=1, that is, if a,ma,m are coprime; it is also unique modulo mm.

Finding a single inverse

The inverse of a single integer can be found in O(log⁡m)O(\log m) 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 O(log⁡min⁡{a,m})O(\log\min\{a,m\}) 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 pp. By Fermat's little theorem, for every a⊥pa\perp p,

a⋅ap−2=ap−1≡1(modp).a\cdot a^{p-2} = a^{p-1} \equiv 1 \pmod p.

By the uniqueness of the inverse, a−1 mod pa^{-1}\bmod p equals ap−2 mod pa^{p-2}\bmod p. Therefore, binary exponentiation can calculate it in O(log⁡p)O(\log p) 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 mm using Euler's theorem, calculating the inverse with aφ(m)−1 mod ma^{\varphi(m)-1}\bmod m. However, finding the Euler totient function φ(m)\varphi(m) for a single value is not easy, so this algorithm is inefficient in general.

Finding multiple inverses

In some situations, the inverses modulo mm of many integers a1,a2,⋯ ,ana_1,a_2,\cdots,a_n must be computed quickly. Solving them one by one takes O(nlog⁡m)O(n\log m) time in total. In fact, processing them together allows all inverses to be found in O(n+log⁡m)O(n+\log m) time.

Consider the prefix products of the sequence {ai}\{a_i\}:

S0=1, Si=aiSi−1, i=1,2,⋯ ,n.S_0 = 1,~ S_i = a_iS_{i-1},~ i=1,2,\cdots,n.

As long as every aia_i is coprime to mm, their product SnS_n is also coprime to mm. Therefore, the algorithm described above can find Sn−1 mod mS_n^{-1}\bmod m. Since the inverse of a product is the product of the inverses, traversing the sequence backwards from Sn−1S_n^{-1} gives the inverse of every SiS_i:

Si−1−1=aiSi−1 mod m, i=n,n−1,⋯ ,1.S_{i-1}^{-1} = a_iS_i^{-1} \bmod m,~ i = n,n-1,\cdots,1.

The inverse of an individual aia_i can then be calculated by

ai−1=Si−1Si−1 mod m, i=1,2,⋯ ,n.a_i^{-1} = S_{i-1}S_i^{-1} \bmod m,~ i = 1,2,\cdots,n.

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 O(n+log⁡m)O(n+\log m).

Linear-time preprocessing of inverses

If the inverses modulo a prime pp of the first nn positive integers are needed, the recurrence discussed in this section can calculate them in O(n)O(n) time. This method is often used to preprocess the reciprocals of the first nn positive integers' factorials when calculating binomial coefficients.

For a positive integer ii with 1<i<p1< i < p, consider Euclidean division:

p=⌊pi⌋i+(p mod i).p = \left\lfloor \dfrac{p}{i} \right\rfloor i + (p\bmod i).

Taking this equation modulo the prime pp gives

0≡⌊pi⌋i+(p mod i)(modp).0 \equiv \left\lfloor \dfrac{p}{i} \right\rfloor i + (p\bmod i) \pmod p.

Multiplying both sides by i−1(p mod i)−1i^{-1}(p\bmod i)^{-1} gives

i−1≡−⌊pi⌋(p mod i)−1(modp).i^{-1} \equiv - \left\lfloor \dfrac{p}{i} \right\rfloor (p\bmod i)^{-1} \pmod p.

This is the formula for computing inverses by a linear-time recurrence. Since p mod i<ip\bmod i < i, it reduces the problem of finding i−1 mod pi^{-1}\bmod p to the smaller problem (p mod i)−1 mod p(p\bmod i)^{-1}\bmod p. Therefore, starting from 1−1 mod p=11^{-1}\bmod p=1 and applying the formula successively for each ii yields the inverses of the first nn integers in O(n)O(n) 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 mm, the m mod im\bmod i obtained in the recurrence is not guaranteed to be coprime to mm, so the (m mod i)−1(m\bmod i)^{-1} required by the recurrence may not exist. For example, let m=8,i=3m=8,i=3. Then m mod i=2m\bmod i = 2, which has no inverse modulo mm.

After obtaining this recurrence, a natural idea is to recursively find the inverse of any number aa. At each recursive call, use the recurrence to reduce it to the inverse of the smaller remainder p mod ap\bmod a, stopping when the remainder becomes 11. The complexity of this approach is not currently clear1, so the conventional method described above is recommended.

Exercises

References and notes

Footnotes

  1. An answer by riteme on Zhihu points out that the theoretically known upper bound for the complexity is O(p1/3+ε)O(p^{1/3+\varepsilon}), while its performance on actual random data is close to O(log⁡p)O(\log p). ↩

This content comes from OI Wiki: Modular Multiplicative Inverse. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.