Nombres premiers bis

Description

En regardant de plus près l'algorithme utilisé dans la fonction 'prems' de pgl10, et après quelques "impressions intermédiaires", j'ai remarqué que la mémoire auxiliaire initialisée est beaucoup plus grande que celle effectivement utilisée.
L'output "ImpressionsIntermediaires.txt" du programme "ImpressionsIntermediaires.cpp" (dans le Zip), et le tableau suivant:
   i-Max = 100, k-Max = 10
   i-Max = 1000, k-Max = 24
   i-Max = 10000, k-Max = 67
   i-Max = 100000, k-Max = 190
   i-Max = 1000000, k-Max = 547
   i-Max = 10000000, k-Max = 1588
le montrent clairement.

On peut donc limiter la taille de la mémoire auxiliaire mp, par exemple à la racine carrée du nombre de nombres premiers demandé.
Voici une adaptation:
int prems(int nnp, int* np) { // par pgl10, adapté par William VOIROL
    const int maxi = INT_MAX, ieme = 105097565;
    int i=5,m,n,s=0,t[]={4,2,4,2,4,6,2,6},len,*mp;
    if(nnp<ieme) m = nnp+1; else m = ieme;
    len = (m < 100) ? 10 : 1+int32_t(sqrt(m));
    mp = new int[len];
    np[0]=1;  np[1]=2;  np[2]=3;  np[3]=5;    np[4]=7;
    mp[0]=1;  mp[1]=4;  mp[2]=9;  mp[3]=5*5;  mp[4]=7*7;
    for(n=11; i<m; n=n+t[s]) {  // 11 13 17 19 23 29 31 37 41 43 47 49 ...
        for(int k=4;;k++) {
            int j = np[k];
            if( n == mp[k] ) break; // Si n est multiple de np[k]
            if( int64_t(j)*j > int64_t(n) ) { // Si aucun np[k] n'a fourni
                np[i++] = n;                  // un diviseur de n, alors
                mp[++k]=np[k]*np[k];
                break;
            }
            if( n > mp[k] ) mp[k] += 2*j;
        }                                     
        if(++s == 8) s=0;
    }
    delete[] mp;   // libérer la mémoire du tableau auxiliaire mp[]
    if(nnp == ieme) np[ieme] = maxi;
    return len;
}
Ce code semble également un peu plus rapide.

Pour une limitation plus précise, on pourrait utiliser <vector> pour définir mp.

De plus, en passant à des unsigned int, il serait possible de presque doubler les capacités de la fonction.
 

PrimeListBin

Divisons la mémoire auxiliaire utilisée (pour le crible d'Eratosthène) par 8 en utilisant des bits à la place de unsigned char pour définir l'array usv de la fonction PrimeList.

En nous référant à:
   ► CodeS-SourceS: Nombres premiers: le crible d'Eratosthène binaire,
utilisons
   #define B8get(u8,idx) (u8[(idx)>>3] & (1<<((idx)&7)) )
   #define B8set0(u8,idx) {u8[(idx)>>3] &= ~(1<<((idx)&7));}
pour les opération binaires nécessaires:
#define B8get(u8,idx)  (u8[(idx)>>3] &   (1<<((idx)&7)) )
#define B8set0(u8,idx) {u8[(idx)>>3] &= ~(1<<((idx)&7));}

unsigned int PrimeListBin(unsigned int N,unsigned int *np) { // array of primes <= N
  unsigned int E=(N+1)/2, M=(E+7)/8, m=E;
  unsigned char *usv=new unsigned char[M];
  memset(usv,255,M);
  for (unsigned int i=1,e=3; e<=N; ++i,e+=2)
    if (B8get(usv,i))
      for (unsigned int j=(N/e-1)/2; j>=i; --j)
        if (B8get(usv,j)) {B8set0(usv,i+e*j); --m;}
  np[0]=2;
  for (unsigned int e=1,k=1; e<E; ++e)
    if (B8get(usv,e)) np[k++]=(e<<1)|1;
  delete[] usv;
  return m;
}
C'est avec plaisir que je constate que le temps d'execution n'est augmenté que d'environ 15% !

Testez vous-mêmes les résultats suivants en exécutant ListeBis.cpp du Zip:
prems:
lst[10]=29, 44 oct, 0 ms
lst[100]=541, 44 oct, 0 ms
lst[1000]=7919, 124 oct, 0 ms
lst[10000]=104729, 400 oct, 1 ms
lst[100000]=1299709, 1264 oct, 28 ms
lst[1000000]=15485863, 4000 oct, 601 ms
lst[10000000]=179424673, 12648 oct, 14795 ms

PrimeList:
lst[9]=29, 15 oct, 0 ms
lst[99]=541, 271 oct, 0 ms
lst[999]=7919, 3960 oct, 0 ms
lst[9999]=104729, 52365 oct, 0 ms
lst[99999]=1299709, 649855 oct, 6 ms
lst[999999]=15485863, 7742932 oct, 78 ms
lst[9999999]=179424673, 89712337 oct, 940 ms

PrimeListBin:
lst[9]=29, 2 oct, 0 ms
lst[99]=541, 34 oct, 0 ms
lst[999]=7919, 495 oct, 0 ms
lst[9999]=104729, 6546 oct, 0 ms
lst[99999]=1299709, 81232 oct, 6 ms
lst[999999]=15485863, 967867 oct, 78 ms
lst[9999999]=179424673, 11214043 oct, 1095 ms

 
Bonne lecture ...
 

Liens

CodeS-SourceS: Nombres premiers
CodeS-SourceS-pgl10: Nombres premiers
CodeS-SourceS: Nombres premiers: essais de division avec liste
CodeS-SourceS: Nombres premiers: PrimeList
CodeS-SourceS: Nombres premiers: le crible d'Eratosthène binaire
 

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.