Las congruencias expresan formalmente que dos enteros dejan el mismo resto al dividir por un módulo. Esta relación permite razonar con clases de números, simplificar cálculos y modelar ciclos de forma rigurosa.
En el tema anterior usamos el módulo para trabajar con restos. Ahora daremos un paso más preciso: en lugar de decir que 17 y 2 tienen el mismo resto al dividir por 5, escribiremos que son congruentes módulo 5.
La congruencia es útil porque conserva exactamente la información que importa en un cálculo modular y descarta las diferencias que son múltiplos completos del módulo. Es el lenguaje de relojes, índices circulares, códigos de control y buena parte de la criptografía.
Sean a y b enteros y sea m un entero positivo. Decimos que a es congruente con b módulo m si m divide a la diferencia a - b. Se escribe:
La condición indica que a - b es un múltiplo de m. Por eso, al dividir a y b por m, ambos terminan con el mismo resto.
El último caso aclara una idea importante: los números negativos no son un problema. Aunque JavaScript devuelva -3 % 5 como -3, matemáticamente -3 y 2 representan la misma clase módulo 5.
Para m positivo, las dos afirmaciones siguientes son equivalentes:
Por ejemplo, al dividir 17 y 42 por 5 se obtiene resto 2 en ambos casos; por lo tanto, 17 ≡ 42 (mod 5). Esta equivalencia permite elegir la definición más cómoda: divisibilidad para demostrar propiedades y restos para calcular ejemplos.
El símbolo ≡ no es el signo =. La igualdad afirma que dos números son el mismo entero; la congruencia afirma que se comportan igual respecto de un módulo determinado.
La segunda línea muestra que siempre debemos indicar el módulo. Una misma pareja de números puede ser congruente para un módulo y no serlo para otro.
Una forma directa de comprobar una congruencia es normalizar ambos residuos y compararlos.
function modulo(a, m) {
if (!Number.isInteger(m) || m <= 0) throw new Error("m debe ser positivo");
return ((a % m) + m) % m;
}
function sonCongruentes(a, b, m) {
return modulo(a, m) === modulo(b, m);
}
console.log(sonCongruentes(17, 2, 5)); // true
console.log(sonCongruentes(-3, 2, 5)); // true
console.log(sonCongruentes(17, 5, 5)); // falseTambién se podría comprobar que (a - b) % m === 0 cuando m es positivo. Normalizar los residuos suele hacer más evidente qué clase representa cada número.
Para un módulo fijo m, la congruencia tiene tres propiedades que definen una relación de equivalencia:
Estas propiedades permiten agrupar los enteros en conjuntos disjuntos cuyos elementos son indistinguibles bajo el módulo elegido. Más adelante estudiaremos las relaciones de equivalencia de forma general.
La demostración se apoya solo en las reglas de divisibilidad. Para la reflexividad, a - a = 0 y cualquier m positivo divide a 0. Para la simetría, si m divide a - b, también divide su opuesto b - a.
Para la transitividad, si a - b = mk y b - c = ml, al sumar obtenemos a - c = m(k + l). Por lo tanto m divide a - c y se concluye que a ≡ c (mod m).
La clase de equivalencia de a módulo m contiene todos los enteros congruentes con a. Se denota [a]m, o simplemente [a] cuando el módulo es claro.
Aunque cada clase contiene infinitos enteros, módulo m solo existen m clases distintas. Se pueden representar con los residuos 0, 1, ..., m - 1.
Los enteros se separan en cinco clases sin superponerse:
Cada entero pertenece a una y solo una de estas clases. En programación, una clase puede verse como todos los valores que llevan al mismo índice circular.
Las congruencias se pueden sumar y restar. Si a ≡ b (mod m) y c ≡ d (mod m), entonces:
La última reducción usa que 6 ≡ 1 (mod 5). En cálculos largos podemos reemplazar valores por residuos pequeños en cualquier paso.
También se preserva la multiplicación: si a ≡ b (mod m) y c ≡ d (mod m), entonces ac ≡ bd (mod m).
Esto explica por qué conviene reducir después de cada operación: trabajar con 2 y 4 es más simple que trabajar con 17 y 9, y el resultado modular es el mismo.
Si a ≡ b (mod m), entonces an ≡ bn (mod m) para todo entero n no negativo. Basta aplicar repetidamente la propiedad de multiplicación.
La regla permite reemplazar bases grandes por representantes pequeños y es fundamental para calcular potencias modulares eficientemente.
Las operaciones permitidas muestran que se puede sustituir un número por otro congruente dentro de un polinomio con coeficientes enteros. Si a ≡ b (mod m), entonces P(a) ≡ P(b) (mod m).
Esta técnica es frecuente en demostraciones de divisibilidad: se analiza un número mediante sus pocos residuos posibles en lugar de revisar todos los enteros.
A diferencia de la aritmética ordinaria, no se puede cancelar cualquier factor de una congruencia. Por ejemplo:
El factor 2 no puede cancelarse porque comparte un divisor con 6. La cancelación es válida cuando el factor es coprimo con el módulo; los próximos temas desarrollarán el máximo común divisor y los inversos modulares que explican esta condición.
Una divisibilidad se puede escribir como una congruencia con cero:
Esta forma compacta es especialmente útil al construir condiciones de validación o demostrar que una expresión siempre es múltiplo de cierto número.
La paridad puede expresarse enteramente mediante congruencias módulo 2. Un número es par si n ≡ 0 (mod 2) e impar si n ≡ 1 (mod 2).
En tres líneas se justifican reglas conocidas de paridad. Este es un buen ejemplo de cómo las congruencias simplifican razonamientos generales.
Como 10 ≡ 1 (mod 9), cualquier potencia de 10 también es congruente con 1 módulo 9. Por eso un número decimal es congruente con la suma de sus dígitos módulo 9.
La conocida regla de sumar dígitos no es un truco aislado: es una consecuencia de las congruencias y de la representación decimal de los números.
Supongamos que una tarea se ejecuta cada 7 días y que el día inicial se codifica como 0. Dos fechas están en la misma posición del ciclo exactamente cuando la diferencia entre sus números de día es congruente con 0 módulo 7.
function mismaPosicionSemanal(diaA, diaB) {
return sonCongruentes(diaA, diaB, 7);
}
console.log(mismaPosicionSemanal(10, 31)); // true: 31 - 10 = 21
console.log(mismaPosicionSemanal(10, 30)); // falseEl ejemplo abstrae el ciclo semanal. Para fechas reales también deben considerarse calendarios y zonas horarias, pero la periodicidad se modela con congruencias.
Algunos identificadores añaden un dígito de control calculado con residuos para detectar errores de escritura. Una versión didáctica puede elegir el dígito necesario para que la suma de todos los dígitos sea congruente con 0 módulo 10.
function digitoDeControlSimple(texto) {
const suma = [...texto].reduce((total, digito) => total + Number(digito), 0);
return modulo(-suma, 10);
}
console.log(digitoDeControlSimple("5724")); // 2
// 5 + 7 + 2 + 4 + 2 = 20, y 20 ≡ 0 (mod 10)Los sistemas reales usan reglas específicas, a menudo con pesos y módulos distintos. La idea común es verificar una congruencia para detectar inconsistencias en los datos.
Las congruencias convierten la intuición de «tener el mismo resto» en una herramienta algebraica precisa. En el próximo tema estudiaremos con más detalle las operaciones en aritmética modular y cómo calcular con clases de residuos.