Ver Mensaje Individual
  #10 (permalink)  
Antiguo 11/07/2014, 08:25
Avatar de leosansan
leosansan
 
Fecha de Ingreso: mayo-2012
Ubicación: GRAN CANARIA
Mensajes: 194
Antigüedad: 12 años, 6 meses
Puntos: 49
Respuesta: Buscando números primos, con la criba de Eratóstenes

Cita:
Iniciado por CalgaryCorpus Ver Mensaje
No me gusta que asignar un valor a una variable, por ejemplo

Código C++:
Ver original
  1. x = 1

tome mas tiempo que preguntar que valor tiene y luego asignarla, por ejemplo

Código C++:
Ver original
  1. if( x == 0 )
  2.    x = 1;

Pero el programa mostrado previamente es una muestra que este comportamiento se da, entonces, tomando partido de eso mismo, y otros cambios, se puede bajar aun mas el tiempo de ejecución

- nums en vez de hacerlo un arreglo de enteros, hacerlo un arreglo de bool
- Preguntar si ya se tiene el valor true, y solo asignárselo cuando no lo sea

Entonces la nueva versión queda así:
...................................
Y esta version deberia tomar menos tiempo que todas las anteriores... creo
Al menos en mis pruebas, asi es
Creo que has llevado mi idea de no tachar más de una vez al éxito total. Lo has bordado con el uso de bool en lugar de int.

Y tanto que toma menos tiempo. Para el caso de 10^8 lo baja en casi 1 segundo.

Ya hemos exprimido al máximo la Criba de Erastótenes.... ¿o tal vez no?.

A bote pronto veo un desperdicio de memoria en los arrays usados:

* nums está dimensionado a N y, como sólo usamos los impares, podríamos bajarlo a N/2.

* prims está dimensionado a N y los primos son sólo una fracción de los impares hasta N.

Con estas dos ideas básicas puede aumentar el límite de primos, antes de que cruja el programa, de 10^8 a 2.745 x 10^9, lo que no está nada mal:

Código C++:
Ver original
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <stdbool.h>
  5. #define N 100000000 /** 2745000000: hasta aqui mi PC calcula los primos **/
  6. #define N_medio N/2  /**........ por ahora...y con este metodo.......... **/
  7.  
  8. int main(){
  9.   unsigned int  i, j , z , x = 0 , N_PRIMS , rq ;
  10.   unsigned int potencias[]={100,1000,10000,100000,1000000,10000000,100000000,1000000000};
  11.   unsigned int Relacion, relacion[]={4,5,8,10,12,15,17,19};
  12.   rq = (int) ( sqrt( N ) );
  13. /** por ejemplo sqrt(1.600.000.000) = 40.000 ==> solo llegamos a 39.999 **/
  14.   if ( rq % 2 == 0 )
  15.     rq--;
  16.   for ( i = 0 ; i < 8 ; i++ )
  17.     if ( N / potencias[i] >= 1 && N / potencias[i] < 10 ){
  18.       Relacion = relacion[i];
  19.       break;
  20.     }
  21.   N_PRIMS = ( N / Relacion );
  22.   bool *nums  = calloc( N_medio , sizeof ( bool ) );
  23.   if( !nums ){
  24.     printf("nums::No hay espacio suficiente en memoria");
  25.     return EXIT_FAILURE;
  26.   }
  27.   unsigned int *prims = calloc( N_PRIMS , sizeof ( unsigned int ) );
  28.   if( !prims ){
  29.     printf("prims::No hay espacio suficiente en memoria");
  30.     return EXIT_FAILURE;
  31.   }
  32.   prims[x] = 2;
  33.   for( i = 3  , z = 1 ; i <= N ; i += 2 , z++ ){
  34.     if( nums[z] )
  35.       continue;
  36.     prims[++x] = i ;
  37.     if( i > rq )
  38.       continue;
  39.     for( j = z + z * i ; j <= N_medio ; j += i ){
  40.       if( !nums[j] )
  41.         nums[j] = true;
  42.     }
  43.   }
  44.   printf( "\n\tHasta %u hay %u numeros primos\n" , N , x + 1 );
  45.   printf( "\n\t\tEl ultimo es: %u \n" , prims[x] );
  46.  
  47.         /***** PARA IMPRIMIR POR GRUPOS *****/
  48.  
  49. /** quita el "+" que aparece al final de la siguiente linea  **/
  50.  
  51. /************************************************************+/
  52.   system ( "pause" );
  53.   char cifra[10] , cad1 [] = "%" , cad2 [] = "u" ;
  54.   unsigned int k = 1 , n1 = N , lineas = 0;
  55.   for(  ;  n1 ; k ++, n1 /= 10 );
  56.   sprintf( cifra , "%s%u%s" , cad1 , k , cad2);
  57.   for( i = 0 , j = 1 ; i <= x ; i ++ , j ++ ){
  58.     if( 90 / j == k )
  59.       putchar ( '\n' ) , j = 1 , lineas++;
  60.     if( lineas == 38 )
  61.       system ( "pause" ) , lineas = 0;
  62.     printf( cifra , prims[i] );
  63.   }
  64.   /*************************************************************/
  65.   free ( nums );
  66.   free ( prims );
  67.   return EXIT_SUCCESS;
  68. }

Hago hincapié en el nuevo for, en lugar de:

Código C++:
Ver original
  1. i2 = i + i ;
  2.     for( j = i * i ; j <= N ; j += i2 )

tengo que usar ahora:

Código C++:
Ver original
  1. for( j = z + z * i ; j <= N_medio ; j += i )

Todo es mirarlo un poco para entenderlo .

Y he aquí algunas salidas para alguno de los valores de N, en mi PC claro, en otros más nuevos y potentes se obtendrán mejores resultados:

Código C++:
Ver original
  1. ..........................................................
  2.         Hasta 100000000 hay 5761455 numeros primos
  3.                 El ultimo es: 99999989
  4.   Process returned 0 (0x0)   execution time : 1.877 s
  5. ..........................................................
  6.         Hasta 1000000000 hay 50847534 numeros primos
  7.                 El ultimo es: 999999937
  8.   Process returned 0 (0x0)   execution time : 21.485 s
  9. ..........................................................
  10.         Hasta 1500000000 hay 74726528 numeros primos
  11.                 El ultimo es: 1499999957
  12.   Process returned 0 (0x0)   execution time : 32.334 s
  13. ..........................................................
  14.         Hasta 2000000000 hay 98222287 numeros primos
  15.                 El ultimo es: 1999999973
  16.   Process returned 0 (0x0)   execution time : 42.225 s
  17. ..........................................................
  18.         Hasta 2500000000 hay 121443371 numeros primos
  19.                 El ultimo es: 2499999977
  20.   Process returned 0 (0x0)   execution time : 54.648 s
  21. ..........................................................
  22.         Hasta 2745000000 hay 132740843 numeros primos
  23.                 El ultimo es: 2744999969
  24.   Process returned 0 (0x0)   execution time : 59.215 s
  25. ..........................................................

Y quedo a la espera de nuevas perspectivas amigo CalgaryCorpus.


Última edición por leosansan; 11/07/2014 a las 11:01