Cálculo del Inverso Multiplicativo Modular

El inverso multiplicativo modular es un concepto fundamental en la teoría de números y tiene amplias aplicaciones en criptografía, informática y matemáticas discretas. Para un entero a y un módulo m, su inverso multiplicativo modular x (si existe) satisface la ecuación:

a * x ≡ 1 (mod m)

Esto significa que (a * x) % m = 1. El inverso existe si y solo si gcd(a, m) = 1 (es decir, a y m son coprimos).

Consideremos un problema clásico: dada la relación N = A % P, donde A % B = 0 y gcd(B, P) = 1, se pide calcular (A / B) % P. Si X = (A / B) % P, entonces se deduce que A / B ≡ X (mod P). Multiplicando por B, tenemos A ≡ B * X (mod P). Dado que N = A % P, podemos reescribir esto como N ≡ B * X (mod P). El objetivo es encontrar X, que es equivalente a encontrar X = N * B^-1 (mod P), donde B^-1 es el inverso multiplicativo de B modulo P.

Para este ejemplo, utilizaremos un módulo primo P = 9973.

Método 1: Búsqueda Exhaustiva (Fuerza Bruta)

La forma más sencilla de encontrar el inverso multiplicativo X para B * X ≡ N (mod P) es probar todos los posibles valores de X desde 0 hasta P-1. Dado que P es relativamente pequeño (9973), este método es viable aunque ineficiente para módulos grandes.

#include <iostream>

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    int casos_prueba;
    std::cin >> casos_prueba;
    while (casos_prueba--) {
        int num_n, denom_b; // N y B en la ecuación N = B * X (mod P)
        std::cin >> num_n >> denom_b;
        num_n %= 9973;
        denom_b %= 9973;
        for (int res_x = 0; res_x < 9973; ++res_x) {
            // Buscamos X tal que (X * B) % P == N
            if ((static_cast<long long>(res_x) * denom_b) % 9973 == num_n) {
                std::cout << res_x << std::endl;
                break;
            }
        }
    }
    return 0;
}

Método 2: Teorema Pequeño de Fermat

Si el módulo P es un número primo y a no es un múltiplo de P (es decir, gcd(a, P) = 1), el Teorema Pequeño de Fermat establece que:

a^(P-1) ≡ 1 (mod P)

Multiplicando ambos lados por a^-1 (el inverso de a), obtenemos:

a^(P-2) ≡ a^-1 (mod P)

Por lo tanto, el inverso multiplicativo de a modulo P se puede calcular como a^(P-2) mod P. Este cálculo requiere una función eficiente para la exponenciación modular (también conocida como "exponenciación rápida" o "potencia binaria").

#include <iostream>

// Función para calcular (base^exponente) % modulo eficientemente
long long calcular_potencia(long long base, long long exponente, long long modulo) {
    long long resultado = 1;
    base %= modulo;
    while (exponente > 0) {
        if (exponente % 2 == 1) { // Si el bit actual del exponente es 1
            resultado = (resultado * base) % modulo;
        }
        base = (base * base) % modulo; // Cuadrar la base
        exponente /= 2; // Desplazar el exponente a la derecha
    }
    return resultado;
}

// Función para calcular el inverso multiplicativo usando Fermat
long long inverso_fermat(long long valor, long long modulo_primo) {
    // El inverso es valor^(modulo_primo - 2) mod modulo_primo
    return calcular_potencia(valor, modulo_primo - 2, modulo_primo);
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    int casos_prueba;
    std::cin >> casos_prueba;
    while (casos_prueba--) {
        long long num_n, denom_b; // N y B
        std::cin >> num_n >> denom_b;
        // Encontramos el inverso de B mod 9973
        long long inv_b = inverso_fermat(denom_b, 9973);
        // Calculamos (N * inv_b) % 9973
        long long resultado_final = (num_n * inv_b) % 9973;
        std::cout << resultado_final << std::endl;
    }
    return 0;
}

Método 3: Algoritmo Extendido de Euclides

El Algoritmo Extendido de Euclides puede encontrar enteros x e y para cualquier par de enteros a y b tales que:

a * x + b * y = gcd(a, b)

Para encontrar el inverso multiplicativo de a modulo m, buscamos x tal que a * x ≡ 1 (mod m). Esto es equivalente a encontrar x e k tales que a * x + m * k = 1. Esto solo es posible si gcd(a, m) = 1. El Algoritmo Extendido de Euclides puede resolver directamente esta ecuación.

La función recursiva euclides_extendido(a, m, x, y) devolverá gcd(a, m) y actualizará x e y con los coeficienets corespondientes. El valor de x obtenido puede ser negativo, por lo que es necesario ajustarlo para que sea positivo y esté dentro del rango [0, m-1] usando (x % m + m) % m.

#include <iostream>

// Implementación del Algoritmo Extendido de Euclides
// Calcula a*x_out + b*y_out = gcd(a, b)
long long euclides_extendido(long long a_val, long long b_val, long long &x_out, long long &y_out) {
    if (b_val == 0) {
        x_out = 1;
        y_out = 0;
        return a_val; // gcd(a, 0) = a
    }
    long long gcd_val = euclides_extendido(b_val, a_val % b_val, y_out, x_out);
    y_out -= (a_val / b_val) * x_out;
    return gcd_val;
}

// Función para calcular el inverso multiplicativo usando Euclides Extendido
long long inverso_euclides(long long valor, long long modulo) {
    long long x_coeff, y_coeff;
    // euclides_extendido(valor, modulo, x_coeff, y_coeff) nos da:
    // valor * x_coeff + modulo * y_coeff = gcd(valor, modulo)
    // Si gcd(valor, modulo) es 1, entonces valor * x_coeff % modulo = 1
    euclides_extendido(valor, modulo, x_coeff, y_coeff);
    // Ajustar x_coeff para que sea positivo
    return (x_coeff % modulo + modulo) % modulo;
}

int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    int casos_prueba;
    std::cin >> casos_prueba;
    while (casos_prueba--) {
        long long num_n, denom_b; // N y B
        std::cin >> num_n >> denom_b;
        // Encontramos el inverso de B mod 9973
        long long inv_b = inverso_euclides(denom_b, 9973);
        // Calculamos (N * inv_b) % 9973
        long long resultado_final = (num_n * inv_b) % 9973;
        std::cout << resultado_final << std::endl;
    }
    return 0;
}

Etiquetas: modular arithmetic Multiplicative Inverse Fermat's Little Theorem Extended Euclidean Algorithm Number Theory

Publicado el 6-28 21:54