En el proceso de aprender el lenguaje C, «la determinación de números primos» es uno de los problemas básicos que aparece con frecuencia. Para principiantes en programación, representa una buena oportunidad para adquirir la «capacidad de entender las propiedades de los números y seleccionar el algoritmo apropiado». Además, al aprender algoritmos de determinación de primos más eficientes, se profundiza la comprensión de las diferencias en la complejidad computacional de los algoritmos y la optimización de programas. En este artículo, introducimos métodos para determinar números primos usando el lenguaje C y proporcionamos código de muestra que funciona en la práctica. Cubrimos diversas técnicas, desde el método básico de prueba de división hasta el tamiz de Eratóstenes más rápido.
2. ¿Qué es un número primo?
Un número primo es un número natural que no tiene divisores positivos aparte de 1 y él mismo. Por ejemplo, 2, 3, 5, 7, 11, etc., son números primos.
2.1. Características básicas de los números primos
El menor número primo es 2 (el único número primo par)
1 no es un número primo (porque solo tiene un divisor)
Existen infinitos números primos
Si un entero n mayor o igual a 2 no es primo, entonces es divisible por un primo mayor o igual a 2
2.2. Ejemplos concretos de números primos
Número
Si es primo
2
✅ Primo
3
✅ Primo
4
❌ Número compuesto (2×2)
5
✅ Primo
6
❌ Número compuesto (2×3)
7
✅ Primo
8
❌ Número compuesto (2×4)
9
❌ Número compuesto (3×3)
3. Método básico para determinar números primos en C (🔰 Para principiantes)
Aquí introducimos el método más básico, el«método de prueba de división».
3.1. Método de prueba de división (básico)
El método de prueba de división consiste en verificar, para un enteroN mayor o igual a 2, si esdivisible por algún entero distinto de 1 y de N mismo.
Si N es un entero mayor o igual a 2, verificar si es divisible por números desde 2 hasta N-1
Si hay un número que divide exactamente, es un «número compuesto»; si no, es un «número primo»
Código de muestra (versión básica)
#include
int is_prime(int n) {
if (n < 2) return 0; // Los números menores o iguales a 1 no son primos
for (int i = 2; i < n; i++) { // Verificar si es divisible desde 2 hasta n-1
if (n % i == 0) return 0;
}
return 1;
}
int main() {
int num = 7;
if (is_prime(num))
printf("%d es un número primon", num);
else
printf("%d no es un número primon", num);
return 0;
}
Resultado de la ejecución
7 es un número primo
Este método es simple y fácil de entender, pero tiene la desventaja de que, al tener una complejidad computacional de O(N) que es grande, el tiempo de procesamiento se alarga cuando N es grande. En la siguiente sección, introduciremos métodos más eficientes.
4. Método eficiente para determinar números primos en C [Criba de Eratóstenes – Versión mejorada del método de prueba de división]
Para optimizar el cálculo de la determinación de números primos, explicaremos los siguientes dos métodos.
Método de prueba de división hasta √N (optimizado)
Criba de Eratóstenes (sieve)
4.1. Método de prueba de división hasta √N (optimizado)
Para un número N que no es primo, siempre existe un divisor menor o igual a √N, por lo que el punto clave es que solo necesitamos verificar el rango hasta la raíz cuadrada de N. Código de muestra
#include
#include
int is_prime_optimized(int n) {
if (n < 2) return 0;
if (n % 2 == 0 && n != 2) return 0; // Los números pares no son primos excepto 2
for (int i = 3; i <= sqrt(n); i += 2) { // Solo verificar números impares (saltar pares)
if (n % i == 0) return 0;
}
return 1;
}
int main() {
int num = 29;
if (is_prime_optimized(num))
printf("%d es un número primo\n", num);
else
printf("%d no es un número primo\n", num);
return 0;
}
Resultado de ejecución
29 es un número primo
Con este método, la complejidad computacional se mejora de O(N) → O(√N), permitiendo una determinación rápida incluso para números grandes.
4.2. Criba de Eratóstenes (sieve)
La criba de Eratóstenes es un algoritmo que «elimina los múltiplos de pequeños números primos para encontrar números primos de manera eficiente».
Comenzar con 2 y eliminar todos sus múltiplos
Luego, eliminar los múltiplos del número mínimo restante (3)
Repitiendo esto, solo quedan los números primos
Código de muestra
#include
#include
void sieve(int n) {
bool prime[n + 1];
for (int i = 0; i <= n; i++) prime[i] = true;
for (int p = 2; p * p <= n; p++) {
if (prime[p]) {
for (int i = p * p; i <= n; i += p)
prime[i] = false;
}
}
for (int p = 2; p <= n; p++)
if (prime[p])
printf("%d ", p);
printf("\n");
}
int main() {
int n = 50;
sieve(n);
return 0;
}
Resultado de ejecución
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
La complejidad de la criba de Eratóstenes es O(N log log N) y es óptima para encontrar grandes cantidades de números primos.
5. Comparación de rendimiento de algoritmos de determinación de números primos en C [Medición de velocidad y optimización]
Hay varias técnicas diferentes para los algoritmos de determinación de números primos, pero la velocidad de procesamiento y la eficiencia varían considerablemente. En esta sección, mediremos el tiempo de ejecución en C para los siguientes tres métodos y examinaremos en qué escenarios cada técnica es efectiva.
Método de prueba de división (básico): O(N)
Prueba de división hasta √N (optimizado): O(√N)
Criba de Eratóstenes (para encontrar primos en un rango): O(N log log N)
5.1. Método de medición del tiempo de ejecución
En C, para medir el tiempo de procesamiento, se puede utilizar la clock() función.Código de muestra para la medición básica del tiempo de ejecución
#include
#include
void measure_time(void (*func)(int), int n) {
clock_t start, end;
start = clock(); // Inicio de medición
func(n); // Ejecutar la función objetivo de medición
end = clock(); // Fin de medición
printf("Execution time: %lf secondsn", (double)(end - start) / CLOCKS_PER_SEC);
}
5.2. Medición del tiempo de ejecución de cada método
5.2.1. Método de prueba de división (O(N))
Código
int is_prime(int n) {
if (n < 2) return 0;
for (int i = 2; i < n; i++) {
if (n % i == 0) return 0;
}
return 1;
}
void test_trial_division(int limit) {
int count = 0;
for (int i = 2; i <= limit; i++) {
if (is_prime(i)) count++;
}
printf("Total primes: %dn", count);
}
5.3. Comparación del tiempo de ejecución (graficado)
Método
Complejidad computacional
Para 10,000
Para 100,000
Para 1,000,000
Método de prueba de división
O(N)
0.25 segundos
2.5 segundos
Decenas de segundos a varios minutos
Prueba de división hasta √N
O(√N)
0.02 segundos
0.15 segundos
1.5 segundos
Criba de Eratóstenes
O(N log log N)
0.001 segundos
0.005 segundos
0.03 segundos
Se puede ver que la Criba de Eratóstenes es abrumadoramente más rápida.
6. Preguntas frecuentes (FAQ)
En esta sección, responderemos a las preguntas más comunes sobre la determinación de números primos en C.
Q1: ¿Por qué se usa la raíz cuadrada en la determinación de números primos?
A: Si un número N no es primo, siempre existe un divisor menor o igual a la raíz cuadrada de N, según una propiedad matemática. Por ejemplo, en el caso de N = 49, las parejas de divisores son las siguientes.
1 × 49
7 × 7 (raíz cuadrada)
49 × 1
Los divisores que exceden la raíz cuadrada ya han sido verificados en etapas anteriores, por lo que se puede reducir la complejidad computacional de O(N) a O(√N).
Q2: ¿En qué situaciones se debe usar el tamiz de Eratóstenes?
A: El tamiz de Eratóstenes es ideal cuando se desea encontrar rápidamente todos los números primos en un rango determinado. ✅Casos en los que se debe usar el tamiz de Eratóstenes
Quiero listar los números primos desde 1 hasta 1 millón
Quiero realizar la determinación de primos para múltiples números de manera eficiente
Q3: ¿La velocidad de la determinación de primos cambia según el entorno de C?
A: Sí, la velocidad de la determinación de primos varía considerablemente según el compilador, opciones de optimización y entorno de ejecución de C. ✅Elementos que influyen
Tipo de compilador (GCC, Clang, MSVC, etc.)
Opciones de optimización durante la compilación
Rendimiento de la CPU (especialmente afecta la velocidad del procesamiento de bucles)
💡Consejos para acelerar
gcc -O3 prime.c -o prime
De esta manera, el compilador optimiza los bucles, lo que puede hacer que el procesamiento sea más rápido.
7. Resumen y direcciones de aprendizaje futuras
En las secciones anteriores, hemos explicado en detalle el uso del lenguaje C parala determinación de números primos desde los fundamentos hasta las aplicaciones.
7.1. Resumen general del artículo
🔹 ¿Qué es un número primo?
número natural que no tiene divisores aparte de 1 y él mismo
Si verificamos hasta la raíz cuadrada, podemos reducir cálculos innecesarios (complejidad O(√N))
🔹 Métodos de determinación de números primos en C
Método
Complejidad
Características
Método de prueba de división (básico)
O(N)
Adecuado para principiantes. Simple pero lento
Método de prueba de división hasta √N
O(√N)
Óptimo para la determinación de un solo número primo
Criba de Eratóstenes
O(N log log N)
Óptimo para encontrar un gran número de primos
🔹 Selección del algoritmo óptimo
Propósito
Algoritmo recomendado
Determinar si un número es primo
Método de prueba de división √N
Creación de lista de primos en un rango
Criba de Eratóstenes
Determinación de números grandes por encima de 10^9
Método Miller-Rabin (probabilístico)
7.2. Direcciones para el aprendizaje futuro
1️⃣ Algoritmos de determinación de primos más avanzados
Método de determinación de primos Miller-Rabin (probabilístico)
Método de determinación de primos AKS (determinístico)
2️⃣ Técnicas de optimización en C
Opciones de optimización del compilador (-O2, -O3)
Procesamiento paralelo utilizando multihilo
3️⃣ Manejo de números grandes en C
Usar la biblioteca GMP (GNU Multiple Precision)
7.3. Ideas de proyectos prácticos
✅Proyecto 1: Contador de primos✅Proyecto 2: Herramienta de factorización prima✅Proyecto 3: Aplicación de exploración de primos
7.4. Resumen
El método de prueba de división (básico) tiene una complejidad de O(N) y es lento, por lo que no es adecuado para números grandes.
El método de prueba de división √N tiene O(√N) y es adecuado para la determinación individual de números grandes.
La criba de Eratóstenes tiene O(N log log N) y permite obtener listas de primos rápidamente.
¡Es importante seleccionar el algoritmo óptimo según el uso!