La criba de Eratóstenes enumera todos los primos hasta un límite superior n, incluido. Estos programas en Rust imprimen los 168 primos menores o iguales a 1000. El límite está incluido; 0 y 1 no son primos.
Pasos de la criba y por qué se empieza en el cuadrado
- Reserva
n + 1elementos booleanos para usar los índices de 0 an. La versión básica los inicializa a verdadero y marca 0 y 1 como falsos. Si el límite es menor que 2, devuelve un resultado vacío antes de acceder al índice 1. - Examina los candidatos
pen orden creciente, empezando por 2. Si la marca sigue siendo verdadera,pes primo: marca como falsos sus múltiplos desde \(p^2\), avanzando depenp. No marques el propiop. - Basta con eliminar múltiplos para los candidatos que cumplen \(p^2\le n\), porque todo compuesto tiene un factor primo menor o igual que su raíz cuadrada.
- Al final, recorre de 2 a
ne imprime todos los números que conservan la marca verdadera. El rango de salida no se limita a la raíz cuadrada.
Un múltiplo \(kp\) menor que \(p^2\), con \(2\le k<p\), ya fue eliminado por un factor primo de k menor que p. Esto no significa que todos los números menores ya se hayan enumerado.

Imagen: SKopp, versión actualizada por Suricata, Wikimedia Commons, CC BY-SA 3.0. El archivo no se ha modificado. La ilustración abarca de 2 a 120; los programas siguientes usan un límite de 1000.
Implementación básica en Rust
| |
Guarda como sieve.rs y compila con rustc --edition=2021 sieve.rs -o sieve. En Windows, usa sieve.exe como nombre del ejecutable. Al ejecutarlo se imprimen 168 líneas: la primera contiene 2 y la última, 997. Estos ejemplos se ejecutaron con Rust 1.90.0.
sieve(0) y sieve(1) devuelven un vector vacío; sieve(2) devuelve [2]. La condición p <= n / p hace que p * p se evalúe solo cuando el cuadrado está dentro del límite. Antes de sumar el siguiente múltiplo se comprueba la distancia restante. No se necesita una raíz cuadrada en coma flotante.
Versión que elimina solo candidatos impares
Los pares mayores que 2 son compuestos. Podemos marcar 2 como verdadero e inicializar solo los impares como candidatos. Para un primo impar p, su cuadrado es impar; avanzar desde él en pasos de \(2p\) visita únicamente múltiplos impares.
| |
Guarda esta versión en otro archivo y compílala. Imprime los mismos 168 primos, devuelve un resultado vacío para 0 y 1, y [2] para 2. No combines los dos main en un mismo archivo.
Esta versión omite parte del trabajo con los pares. Sin embargo, inicializar a falso no garantiza mayor velocidad. El tiempo depende de la inicialización, las escrituras, el acceso a memoria, el compilador y la máquina. Aquí no se comparan tiempos medidos. El arreglo sigue teniendo n + 1 elementos para que los índices correspondan directamente a los números.
Complejidad y límites de uso
En el modelo RAM habitual, la criba necesita tiempo \(O(n\log\log n)\) y espacio \(O(n)\) para las marcas. Son estimaciones asintóticas de operaciones y almacenamiento, no tiempos medidos ni complejidad en bits para enteros de precisión arbitraria. El ejercicio de la criba del material de análisis de Princeton también indica este crecimiento.
En Rust, bool ocupa un byte y Vec<T> almacena elementos contiguos. Este Vec<bool> no es un arreglo de bits empaquetados. Hay n + 1 marcas lógicas; los metadatos del vector, la capacidad reservada y el Vec<usize> devuelto también requieren memoria.
Si no se puede representar n + 1, checked_add devuelve None, y el expect que sigue provoca un panic. En los demás casos sigue siendo necesario disponer de suficiente memoria; no se admiten límites arbitrariamente grandes. Para intervalos grandes, considera una criba segmentada. Enumerar primos en un rango tiene un propósito distinto de comprobar un solo entero grande.
