Tests de primalidad
Este artículo describe varios algoritmos para determinar si un número es primo o no.
División por tentativa
Por definición, un número primo no tiene ningún divisor distinto de y de sí mismo. Un número compuesto tiene al menos un divisor adicional; llamémoslo . Naturalmente también es un divisor de . Es fácil ver que o bien o bien , por lo tanto uno de los divisores y es . Podemos usar esta información para comprobar la primalidad.
Intentamos hallar un divisor no trivial, comprobando si alguno de los números entre y es un divisor de . Si es un divisor, entonces definitivamente no es primo; en caso contrario, lo es.
bool isPrime(int x) {
for (int d = 2; d * d <= x; d++) {
if (x % d == 0)
return false;
}
return x >= 2;
}Esta es la forma más simple de una comprobación de primalidad. Se puede optimizar esta función bastante, por ejemplo comprobando solo todos los números impares en el bucle, ya que el único primo par es 2. Varias de esas optimizaciones se describen en el artículo sobre factorización de enteros.
Test de primalidad de Fermat
Este es un test probabilístico.
El pequeño teorema de Fermat (véase también la función φ de Euler) afirma que, para un número primo y un entero coprimo, se cumple la siguiente ecuación:
En general este teorema no se cumple para números compuestos.
Esto se puede usar para crear un test de primalidad. Elegimos un entero y comprobamos si la ecuación se cumple o no. Si no se cumple, p. ej. , sabemos que no puede ser un número primo. En este caso llamamos a la base un testigo de Fermat (Fermat witness) de que es compuesto.
Sin embargo también es posible que la ecuación se cumpla para un número compuesto. Así que si la ecuación se cumple, no tenemos una demostración de primalidad. Solo podemos decir que es probablemente primo. Si resulta que el número es en realidad compuesto, llamamos a la base un mentiroso de Fermat (Fermat liar).
Ejecutando el test para todas las bases posibles, de hecho podemos demostrar que un número es primo. Sin embargo esto no se hace en la práctica, ya que es mucho más trabajo que simplemente hacer división por tentativa. En su lugar, el test se repetirá varias veces con elecciones aleatorias de . Si no encontramos ningún testigo de que el número es compuesto, es muy probable que de hecho sea primo.
bool probablyPrimeFermat(int n, int iter=5) {
if (n < 4)
return n == 2 || n == 3;
for (int i = 0; i < iter; i++) {
int a = 2 + rand() % (n - 3);
if (binpower(a, n - 1, n) != 1)
return false;
}
return true;
}Usamos exponenciación binaria para calcular de forma eficiente la potencia .
Hay una mala noticia, sin embargo: existen algunos números compuestos para los que se cumple para todo coprimo con , por ejemplo para el número . Tales números se llaman números de Carmichael. El test de primalidad de Fermat solo puede identificar estos números si tenemos una inmensa suerte y elegimos una base con .
El test de Fermat se sigue usando en la práctica, ya que es muy rápido y los números de Carmichael son muy raros. P. ej. solo existen 646 de esos números por debajo de .
Test de primalidad de Miller-Rabin
El test de Miller-Rabin extiende las ideas del test de Fermat.
Para un número impar , es par y podemos extraer todas las potencias de 2. Podemos escribir:
Esto nos permite factorizar la ecuación del pequeño teorema de Fermat:
Si es primo, entonces tiene que dividir a uno de estos factores. Y en el test de primalidad de Miller-Rabin comprobamos exactamente esa afirmación, que es una versión más estricta de la afirmación del test de Fermat. Para una base comprobamos si o bien
se cumple, o bien
se cumple para algún .
Si encontramos una base que no satisface ninguna de las igualdades anteriores, entonces encontramos un testigo de que es compuesto. En este caso hemos demostrado que no es un número primo.
De forma similar al test de Fermat, también es posible que el conjunto de ecuaciones se cumpla para un número compuesto. En ese caso la base se llama un mentiroso fuerte (strong liar). Si una base satisface las ecuaciones (una de ellas), es solo primo probable fuerte (strong probable prime). Sin embargo, no hay números como los de Carmichael, en los que todas las bases no triviales mientan. De hecho es posible mostrar que a lo sumo de las bases pueden ser mentirosos fuertes. Si es compuesto, tenemos una probabilidad de de que una base aleatoria nos diga que es compuesto. Haciendo varias iteraciones, eligiendo distintas bases aleatorias, podemos decir con probabilidad muy alta si el número es verdaderamente primo o si es compuesto.
Aquí hay una implementación para enteros de 64 bits.
using u64 = uint64_t;
using u128 = __uint128_t;
u64 binpower(u64 base, u64 e, u64 mod) {
u64 result = 1;
base %= mod;
while (e) {
if (e & 1)
result = (u128)result * base % mod;
base = (u128)base * base % mod;
e >>= 1;
}
return result;
}
bool check_composite(u64 n, u64 a, u64 d, int s) {
u64 x = binpower(a, d, n);
if (x == 1 || x == n - 1)
return false;
for (int r = 1; r < s; r++) {
x = (u128)x * x % n;
if (x == n - 1)
return false;
}
return true;
};
bool MillerRabin(u64 n, int iter=5) { // devuelve true si n es probablemente primo; si no, devuelve false.
if (n < 4)
return n == 2 || n == 3;
int s = 0;
u64 d = n - 1;
while ((d & 1) == 0) {
d >>= 1;
s++;
}
for (int i = 0; i < iter; i++) {
int a = 2 + rand() % (n - 3);
if (check_composite(n, a, d, s))
return false;
}
return true;
}Antes del test de Miller-Rabin se puede comprobar adicionalmente si alguno de los primeros números primos es un divisor. Esto puede acelerar mucho el test, ya que la mayoría de los números compuestos tienen divisores primos muy pequeños. P. ej. el de todos los números tiene un factor primo menor que .
Versión determinista
Miller mostró que es posible hacer el algoritmo determinista comprobando solo todas las bases . Bach dio después una cota concreta: solo es necesario probar todas las bases .
Esto sigue siendo una cantidad bastante grande de bases. Así que se ha invertido bastante poder de cómputo en hallar cotas más bajas. Resulta que, para probar un entero de 32 bits, solo es necesario comprobar las primeras 4 bases primas: 2, 3, 5 y 7. El menor número compuesto que falla este test es . Y para probar un entero de 64 bits basta con comprobar las primeras 12 bases primas: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31 y 37.
Esto da lugar a la siguiente implementación determinista:
bool MillerRabin(u64 n) { // devuelve true si n es primo; si no, devuelve false.
if (n < 2)
return false;
int r = 0;
u64 d = n - 1;
while ((d & 1) == 0) {
d >>= 1;
r++;
}
for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
if (n == a)
return true;
if (check_composite(n, a, d, r))
return false;
}
return true;
}También es posible hacer la comprobación con solo 7 bases: 2, 325, 9375, 28178, 450775, 9780504 y 1795265022. Sin embargo, como estos números (excepto 2) no son primos, hay que comprobar adicionalmente si el número que se está comprobando es igual a algún divisor primo de esas bases: 2, 3, 5, 13, 19, 73, 193, 407521, 299210837.