CP Algorithms ES

Tabla de contenido

Inverso multiplicativo modular

Definición

Un inverso multiplicativo modular de un entero $a$ es un entero $x$ tal que $a \cdot x$ es congruente con $1$ en algún módulo $m$. Para escribirlo de manera formal: queremos encontrar un número entero $x$ tal que \(a \cdot x \equiv 1 \mod m.\) También denotaremos $x$ simplemente con $a^{-1}$.

Debemos tener en cuenta que el inverso modular no siempre existe. Por ejemplo, sea $m = 4$, $a = 2$. Al verificar todos los valores posibles módulo $m$ queda claro que no podemos encontrar $a^{-1}$ que satisfaga la ecuación anterior. Se puede probar que el inverso modular existe si y solo si $a$ y $m$ son primos relativos (es decir, $\gcd(a, m) = 1$).

En este artículo, presentamos dos métodos para encontrar el inverso modular en caso de que exista, y un método para encontrar el inverso modular para todos los números en tiempo lineal.

Encontrar el inverso modular usando el algoritmo euclidiano extendido

Considere la siguiente ecuación (con $x$ y $y$ desconocidos):

\[a \cdot x + m \cdot y = 1\]

Ésta es una Ecuación lineal diofántica en dos variables. Como se muestra en el artículo vinculado, cuando $\gcd(a, m) = 1$, la ecuación tiene una solución que se puede encontrar usando el Algoritmo Euclidiano Extendido. Tenga en cuenta que $\gcd(a, m) = 1$ también es la condición para que exista el inverso modular.

Ahora, si tomamos el módulo $m$ de ambos lados, podemos deshacernos de $m \cdot y$, y la ecuación se convierte en:

\[a \cdot x \equiv 1 \mod m\]

Por tanto, el inverso modular de $a$ es $x$.

La implementación es la siguiente:

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

Observe que la forma en que modificamos x. La x resultante del algoritmo euclidiano extendido puede ser negativa, por lo que x % m también puede ser negativa, por lo tanto tenemos que sumar m para que sea positiva.

Encontrar el inverso modular usando exponenciación binaria

Otro método para encontrar el inverso modular es usar el teorema de Euler, que establece que la siguiente congruencia es verdadera si $a$ y $m$ son primos relativos:

\[a^{\phi (m)} \equiv 1 \mod m\]

$\phi$ es la función Totient de Euler. Una vez más, tenga en cuenta que el hecho de que $a$ y $m$ sean primos relativos también fue la condición para que exista el inverso modular.

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

\[a^{m - 1} \equiv 1 \mod m\]

Multiplica ambos lados de las ecuaciones anteriores por $a^{-1}$, y obtenemos:

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

Aunque este método es más fácil de entender que el método descrito en el párrafo anterior, en el caso de que $m$ no sea un número primo, necesitamos calcular la función phi de Euler, que implica la factorización de $m$, lo que puede ser muy difícil. Si se conoce la factorización prima de $m$, entonces la complejidad de este método es $O(\log m)$.

Encontrar el inverso modular para cada número módulo $m$

El problema es el siguiente: queremos calcular el inverso modular para cada número en el rango $[1, m-1]$.

Aplicando los algoritmos descritos en los apartados anteriores, podemos obtener una solución con complejidad $O(m \log m)$.

Aquí presentamos un algoritmo mejor con complejidad $O(m)$. Sin embargo, para este algoritmo específico, requerimos que el módulo $m$ sea primo.

Denotamos por $\text{inv}[i]$ el inverso modular de $i$. Entonces para $i>1$ la siguiente ecuación es válida:

\[\text{inv}[i] = - \left\lfloor \frac{m}{i} \right\rfloor \cdot \text{inv}[m \bmod i] \bmod m\]

Por tanto, la implementación es muy sencilla:

inv[1] = 1;
for(int i = 2; i < m; ++i)
    inv[i] = m - (m/i) * inv[m%i] % m;

Prueba

Tenemos: \(m \bmod i = m - \left\lfloor \frac{m}{i} \right\rfloor \cdot i\) Tomando ambos lados módulo $m$ produce: \(m \bmod i \equiv - \left\lfloor \frac{m}{i} \right\rfloor \cdot i \mod m\) Multiplica ambos lados por $i^{-1} \cdot (m \bmod i)^{-1}$ produce: \((m \bmod i) \cdot i^{-1} \cdot (m \bmod i)^{-1} \equiv -\left\lfloor \frac{m}{i} \right\rfloor \cdot i \cdot i^{-1} \cdot (m \bmod i)^{-1} \mod m,\) que se simplifica a: \(i^{-1} \equiv -\left\lfloor \frac{m}{i} \right\rfloor \cdot (m \bmod i)^{-1} \mod m,\)

Problemas de Práctica