¡Explicación completa de la detección de primos en C! Prueba de división, criba de Eratóstenes y optimización

目次

1. Introducción

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úmeroSi 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.
  1. Método de prueba de división hasta √N (optimizado)
  2. 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étodoComplejidad computacionalPara 10,000Para 100,000Para 1,000,000
Método de prueba de divisiónO(N)0.25 segundos2.5 segundosDecenas de segundos a varios minutos
Prueba de división hasta √NO(√N)0.02 segundos0.15 segundos1.5 segundos
Criba de EratóstenesO(N log log N)0.001 segundos0.005 segundos0.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étodoComplejidadCaracterí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 √NO(√N)Óptimo para la determinación de un solo número primo
Criba de EratóstenesO(N log log N)Óptimo para encontrar un gran número de primos

🔹 Selección del algoritmo óptimo

PropósitoAlgoritmo recomendado
Determinar si un número es primoMétodo de prueba de división √N
Creación de lista de primos en un rangoCriba de Eratóstenes
Determinación de números grandes por encima de 10^9Mé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 primosProyecto 2: Herramienta de factorización primaProyecto 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!
侍エンジニア塾