Skip to Content

Inverso multiplicativo modular

Definición

Un inverso multiplicativo modular  de un entero aa es un entero xx tal que axa \cdot x es congruente con 11 módulo algún módulo mm. De forma formal: queremos encontrar un entero xx tal que

ax1modm.a \cdot x \equiv 1 \mod m.

También denotaremos xx simplemente como a1a^{-1}.

Hay que notar que el inverso modular no siempre existe. Por ejemplo, sea m=4m = 4, a=2a = 2. Al revisar todos los valores posibles módulo mm, queda claro que no podemos encontrar un a1a^{-1} que satisfaga la ecuación anterior. Se puede demostrar que el inverso modular existe si y solo si aa y mm son coprimos (es decir, gcd(a,m)=1\gcd(a, m) = 1).

En este artículo presentamos dos métodos para calcular el inverso modular cuando existe, y un método para calcular el inverso modular de todos los números en tiempo lineal.

Cálculo del inverso modular usando el algoritmo de Euclides extendido

Consideremos la siguiente ecuación (con incógnitas xx e yy):

ax+my=1a \cdot x + m \cdot y = 1

Esta es una ecuación diofántica lineal en dos variables. Como se muestra en el artículo enlazado, cuando gcd(a,m)=1\gcd(a, m) = 1, la ecuación tiene una solución que se puede encontrar con el algoritmo de Euclides extendido. Nótese que gcd(a,m)=1\gcd(a, m) = 1 es también la condición para que exista el inverso modular.

Ahora, si tomamos módulo mm en ambos lados, podemos eliminar mym \cdot y, y la ecuación queda:

ax1modma \cdot x \equiv 1 \mod m

Así, el inverso modular de aa es xx.

La implementación es la siguiente:

int x, y; int g = extended_euclidean(a, m, x, y); if (g != 1) { cout << "No solution!"; } else { x = (x % m + m) % m; cout << x << endl; }

Nótese cómo modificamos x. El x que resulta del algoritmo de Euclides extendido puede ser negativo, así que x % m también podría ser negativo, y primero hay que sumarle m para que quede positivo.

## Cálculo del inverso modular usando exponenciación binaria

Otro método para calcular el inverso modular es usar el teorema de Euler, que afirma que la siguiente congruencia es cierta si aa y mm son coprimos:

aϕ(m)1modma^{\phi (m)} \equiv 1 \mod m

ϕ\phi es la función φ de Euler. De nuevo, nótese que el hecho de que aa y mm sean coprimos era también la condición para que exista el inverso modular.

Si mm es un número primo, esto se simplifica al pequeño teorema de Fermat :

am11modma^{m - 1} \equiv 1 \mod m

Si multiplicamos ambos lados de las ecuaciones anteriores por a1a^{-1}, obtenemos:

  • Para un módulo mm arbitrario (pero coprimo): aϕ(m)1a1modma ^ {\phi (m) - 1} \equiv a ^{-1} \mod m
  • Para un módulo primo mm: am2a1modma ^ {m - 2} \equiv a ^ {-1} \mod m

A partir de estos resultados, podemos calcular fácilmente el inverso modular con el algoritmo de exponenciación binaria, que trabaja en tiempo O(logm)O(\log m).

Aunque este método es más fácil de entender que el del párrafo anterior, cuando mm no es un número primo hay que calcular la función φ de Euler, lo que implica factorizar mm, y eso puede ser muy difícil. Si se conoce la factorización prima de mm, la complejidad de este método es O(logm)O(\log m).

## Cálculo del inverso modular para módulos primos usando división euclidiana

Dado un módulo primo m>am > a (o podemos aplicar el módulo para hacerlo más chico en 1 paso), según la división euclidiana 

m=ka+rm = k \cdot a + r

donde k=mak = \left\lfloor \frac{m}{a} \right\rfloor y r=mmodar = m \bmod a, entonces

    0ka+rmodm    rkamodm    ra1kmodm    a1kr1modm amp;    amp;0amp;ka+ramp;modmamp;    amp;ramp;kaamp;modmamp;    amp;ra1amp;kamp;modmamp;    amp;a1amp;kr1amp;modm\begin{align*} &amp; \implies &amp; 0 &amp; \equiv k \cdot a + r &amp; \mod m \ &amp; \iff &amp; r &amp; \equiv -k \cdot a &amp; \mod m \ &amp; \iff &amp; r \cdot a^{-1} &amp; \equiv -k &amp; \mod m \ &amp; \iff &amp; a^{-1} &amp; \equiv -k \cdot r^{-1} &amp; \mod m \end{align*}

Nótese que este razonamiento no vale si mm no es primo, porque la existencia de a1a^{-1} no implica la existencia de r1r^{-1} en el caso general. Para verlo, intentemos calcular 515^{-1} módulo 1212 con la fórmula anterior. Quisiéramos llegar a 55, ya que 551mod125 \cdot 5 \equiv 1 \bmod 12. Sin embargo, 12=25+212 = 2 \cdot 5 + 2, y tenemos k=2k=2 y r=2r=2, y 22 no es invertible módulo 1212.

Si el módulo es primo, en cambio, todos los aa con 0<a<m0 < a < m son invertibles módulo mm, y podemos usar la siguiente función recursiva (en C++) para calcular el inverso modular del número aa respecto de mm

int inv(int a) { return a <= 1 ? a : m - (long long)(m/a) * inv(m % a) % m; }

La complejidad temporal exacta de esta recursión no se conoce. Está en algún punto entre O(logmloglogm)O(\frac{\log m}{\log\log m}) y O(m132177+ϵ)O(m^{\frac{1}{3} - \frac{2}{177} + \epsilon}). Ver On the length of Pierce expansions . En la práctica esta implementación es rápida; por ejemplo, para el módulo 109+710^9 + 7 siempre termina en menos de 50 iteraciones.

Aplicando esta fórmula, también podemos precomputar el inverso modular de cada número en el rango [1,m1][1, m-1] en O(m)O(m).
inv[1] = 1; for(int a = 2; a < m; ++a) inv[a] = m - (long long)(m/a) * inv[m%a] % m;

Cálculo del inverso modular para un arreglo de números módulo mm

Supongamos que nos dan un arreglo y queremos calcular el inverso modular de todos sus números (todos son invertibles). En lugar de calcular el inverso de cada número, podemos ampliar la fracción por el producto de prefijos (excluyéndose a sí mismo) y el producto de sufijos (excluyéndose a sí mismo), y terminar calculando un solo inverso.

xi1=1xi=x1x2xi1prefixi1 1 xi+1xi+2xnsuffixi+1x1x2xi1xixi+1xi+2xn=prefixi1suffixi+1(x1x2xn)1 xi1amp;=1xi=x1x2xi1prefixi1 1 xi+1xi+2xnsuffixi+1x1x2xi1xixi+1xi+2xnamp;=prefixi1suffixi+1(x1x2xn)1\begin{align} x_i^{-1} &amp;= \frac{1}{x_i} = \frac{\overbrace{x_1 \cdot x_2 \cdots x_{i-1}}^{\text{prefix}{i-1}} \cdot 1 \cdot \overbrace{x{i+1} \cdot x_{i+2} \cdots x_n}^{\text{suffix}{i+1}}}{x_1 \cdot x_2 \cdots x{i-1} \cdot x_i \cdot x_{i+1} \cdot x_{i+2} \cdots x_n} \ &amp;= \text{prefix}{i-1} \cdot \text{suffix}{i+1} \cdot \left(x_1 \cdot x_2 \cdots x_n\right)^{-1} \end{align}

En el código podemos armar un arreglo de productos de prefijos (excluyéndose a sí mismo, empezando desde el elemento identidad), calcular el inverso modular del producto de todos los números y después multiplicarlo por el producto de prefijos y el producto de sufijos (excluyéndose a sí mismo). El producto de sufijos se calcula iterando de atrás hacia adelante.

std::vector<int> invs(const std::vector<int> &a, int m) { int n = a.size(); if (n == 0) return {}; std::vector<int> b(n); int v = 1; for (int i = 0; i != n; ++i) { b[i] = v; v = static_cast<long long>(v) * a[i] % m; } int x, y; extended_euclidean(v, m, x, y); x = (x % m + m) % m; for (int i = n - 1; i >= 0; --i) { b[i] = static_cast<long long>(x) * b[i] % m; x = static_cast<long long>(x) * a[i] % m; } return b; }

Problemas de práctica