Crivello di Eratostene
Da Wikipedia, l'enciclopedia libera.
Il crivello di Eratostene un antico procedimento per il calcolo delle tabelle di numeri primi fino ad un certo numero n prefissato. Deve il nome al matematico Eratostene di Cirene, che ne fu l'ideatore. È a tutt'oggi utilizzato come algoritmo di calcolo dei numeri primi da molti programmi per computer; pur non essendo un algoritmo straordinariamente efficiente, infatti, è in compenso piuttosto semplice da tradurre in un qualsiasi linguaggio di programmazione.
[modifica] Algoritmo
Il procedimento è il seguente: si scrivono tutti i naturali a partire da 2 fino n in un elenco detto setaccio (in programmazione spesso l'elenco è implementato da un array). Poi si cancellano (setacciano) tutti i multipli del primo numero del setaccio (escluso lui stesso). Si prosegue così fino ad arrivare in fondo. I numeri che restano sono i numeri primi minori od uguali a n. È come se si utilizzassero dei setacci a maglie via via più larghe: il primo lascia passare solo i multipli di 2, il secondo solo i multipli di 3, e così via.
Nel caso n = 50, ad esempio, il procedimento di setacciatura si conclude con il numero 7 perché 7 è il massimo primo il cui quadrato non supera 50 e si può provare che il procedimento di setacciatura per ricercare i primi fino ad un certo numero n cessa sempre quando si supera la radice quadrata di n. Infatti ogni numero a del setaccio iniziale, contenente tutti i numeri naturali non superiori ad un dato n, cade dal setaccio che corrisponde al più piccolo dei suoi divisori primi.
Se indichiamo con p il più piccolo divisore primo di a si ha:
con
.
Se ne deduce che
da cui p è sempre minore o uguale alla radice quadrata di a.
[modifica] Implementazioni
[modifica] Implementazione in Bashscript
#!/bin/bash # Si deve invocare con un argomento da linea di comando. LIMITE_SUPERIORE=$1 # Da linea di comando. let META=sqrt(LIMITE_SUPERIORE) # Metà del numero massimo. Primi=( '' $(seq $LIMITE_SUPERIORE) ) i=1 until (( ( i += 1 ) > META )) # È sufficiente verificare solo la metà dei numeri. do if [[ -n $Primi[i] ]] then t=$i until (( ( t += i ) > LIMITE_SUPERIORE )) do Primi[t]= done fi done echo ${Primi[*]} exit 0
[modifica] Implementazione in Actionscript 2.0
function crivella(size:Number) { var numeri:Array = new Array(); for (var n:Number = 0; n < size; n++) { numeri.push(1); } for (var i:Number = 2; i < size; i++) { if (numeri[i] == 1) { for (var j:Number = i + i; j < size; j += i) { numeri[j] = 0; } } } for (var m:Number = 2; m < size; m++) { if (numeri[m] == 1) { trace(m); } } } crivella(1000);
[modifica] Implementazione in Python
#! /usr/bin/env python # -*- coding: cp1252 -*- import sys import math # Valore massimo per la visualizzazione dei numeri primi. valore_max = 0 if len(sys.argv) > 1: # Prova a considerare il primo argomento specificato sulla riga di comando. try: valore_max = int(sys.argv[1]) except ValueError: print "Il valore indicato sulla riga di comando non è valido." if valore_max == 0: # Non è stato specificato alcun valore sulla riga di comando, # oppure quello specificato non è valido. Prova a richiederlo interattivamente. while valore_max <= 0: try: valore_max = int(raw_input("Inserire il numero massimo per il calcolo dei numeri primi: ")) if valore_max <= 0: print "Il numero deve essere intero e positivo." except ValueError: print "Il valore deve essere un numero intero e positivo." # Creazione della lista relativa ai numeri naturali da 0 a valore_max. # I valori ad 1 sono relativi a papabili numeri primi (gli indici). crivello = [0] + [1] * valore_max # massimo valore per cui ha senso applicare il crivello. crivello_max = math.sqrt(valore_max) if crivello_max % 1 != 0: crivello_max = int(math.sqrt(valore_max)) + 1 # Il crivello azzera i valori nella lista corrispondenti agli indici non primi. for i in range(2, crivello_max+1): for j in range(2*i, valore_max+1, i): crivello[j] = 0 # Visualizzazione dei numeri primi (gli indici il cui valore è rimasto a 1). print "Numeri primi da 1 a %d" % valore_max fmt = "%" + str(int(math.log(valore_max,10))+1) + "d" for i in range(1, valore_max+1): if crivello[i] != 0: print fmt % i
[modifica] Implementazione in C
#include <stdio.h> #include <stdlib.h> FILE *pfile; /*prototipi funzioni*/ void creafile(void); void crivello_eratostene(long int pvett[], long int *pn); int main() { long int N, *pvett; printf("Software che calcola i numeri primi usando:\nCRIVELLO DI ERATOSTENE\n\n"); printf("Inserire N:\n"); scanf("%ld", &N); if((pvett= (long int*)malloc(N*sizeof(long int))) == NULL) printf("Insufficient memory!\n\n"); else { creafile(); crivello_eratostene(pvett, &N); fclose(pfile); printf("esecuzione terminata con successo!\n\nFile creato\n\n"); free(pvett); /*distruzione dell'array*/ } exit(EXIT_SUCCESS); } /*funzione che crea il file dove salvare i numeri primi*/ void creafile(void) { char nomefile[20]; printf("Nome da dare al file sul quale salvare i dati:\n"); scanf("%s", nomefile); if((pfile= fopen(nomefile, "w")) == NULL) { printf("Errore creazione file!\n\n"); exit(EXIT_FAILURE); } } /*funzione che calcola i numeri primi*/ void crivello_eratostene(long int pvett[], long int *pn) { long int i, j; for(i=2; i< (*pn); i++) pvett[i]= 1; for(i=2; i< (*pn); i++) if(pvett[i]) for(j=i+i; j< (*pn); j+=i) pvett[j]= 0; /*stampo su file*/ for(i=2; i< (*pn); i++) if(pvett[i]) fprintf(pfile,"%ld\n", i); }
[modifica] Implementazione in C con interi a 64 bit
#include <stdio.h> #include <string.h> #include <stdlib.h> #define FPATH "prime_numbers.TXT" char *allocate_memory(__int64 length); void initialize(char *array, __int64 length); void find_prime_numbers(char *array, __int64 length); void strike_out_multiples(char *array, __int64 length, __int64 n); void write_numbers_to_file(char *fpath, char *array, __int64 length); int main() { printf("\n\nCrivello di Eratostene by N0R81X\n\n"); printf("Numero finale: "); __int64 n; scanf("%I64d", &n); char *array = allocate_memory(n); if(array == NULL) { printf("Impossibile allocare %I64d byte di memoria\n", n); getchar(); return 0; } initialize(array, n); find_prime_numbers(array, n); write_numbers_to_file(FPATH, array, n); printf("Calcolo terminato\n"); getchar(); getchar(); return 0; } char *allocate_memory(__int64 length) { // tuoni e fulmini, un intero byte che verra' ulizzato solo come // flag, basterebbe un bit... in futuro bisogna provare a sistemare char *array = (char *)malloc(length); return array; } void initialize(char *array, __int64 length) { // 1 sta ad indicare che il numero e' primo, 0 che non lo e' // inizialmente inizializzzo tutto a 1, poi i numeri non primi // verranno virtualmente eliminati impostando il valore a 0 // i numeri non vengono memorizzati nell'array, viene memorizzato // solamente il fatto che essi siano o non siano primi, la posizione // di questa informazione corrisponde al numero memset(array, 1, length); // 0 ed 1 non sono numeri primi array[0] = 0; array[1] = 0; } void find_prime_numbers(char *array, __int64 length) { __int64 i; for(i = 0; i < length; i++) { // se si pensa che i sia primo, allora i multipli di certo non lo sono, // quindi vanno eliminati (strike out) if(array[i] == 1) strike_out_multiples(array, length, i); } } void strike_out_multiples(char *array, __int64 length, __int64 n) { __int64 i; for(i = n * 2; i < length; i += n) { array[i] = 0; } } void write_numbers_to_file(char *fpath, char *array, __int64 length) { FILE *f = fopen(fpath, "w"); if(f == NULL) return; __int64 i; for(i = 0; i < length; i++) { if(array[i] == 1) { fprintf(f, "%I64d\n", i); } } fclose(f); }
[modifica] Implementazione in C++
#include <iostream> #include <vector> using std::cout; using std::endl; using std::vector; /** * Oggetto funzionale per controllare se un intero m è diverso e multiplo * dell'intero n con cui il Controllo viene inizializzato. */ class Controllo { public: Controllo( const int n ) : n(n) {} bool operator() ( const int m ) const { return (n != m) && (m % n == 0); } private: const int n; }; int main( int argc, char* argv[] ) { // Controllo sui dati in entrata: il primo argomento deve essere un intero maggiore di 2. if( argc < 2 || atoi(argv[1]) < 2 ) { cout << "Uso: " << argv[0] << " n, con n > 1." << endl; return 1; } // Inizializzazione del vettore dei numeri. vector<int> crivello; const int ultimo = atoi(argv[1]); crivello.reserve(ultimo); for( int i = 2; i <= ultimo; ++i ) crivello.push_back(i); // Filtraggio dei numeri non primi secondo la regola del crivello di Eratostene. for( int i = 0; crivello[i]*crivello[i] <= ultimo; ++i ) { Controllo crivellatore( crivello[i] ); crivello.erase( remove_if( crivello.begin(), crivello.end(), crivellatore), crivello.end() ); } // Stampa dei numeri primi risultanti e conclusione. cout << "Numeri primi fino a " << ultimo << ":" << endl; for( int i = 0; i < crivello.size(); ++i ) cout << crivello[i] << endl; return 0; }
[modifica] Implementazione in C#
using System; namespace Eratostene { class Program { static void Main() { string txt; int max; //Chiedo un valore all'utente do { Console.Write("Cerca numeri primi fino a: "); txt = Console.ReadLine(); } while (!int.TryParse(txt, out max) || max < 2); //fino a che inserisce un valore valido //Calcolo i numeri primi salvandoli in un vettore int[] numeriPrimi = NumeriPrimi.CrivelloEratostene(max); //Visualizzo a schermo i numeri primi trovati Console.Write("Numeri primi:\n"); for (int i = 0; i < numeriPrimi.Length; i++) { Console.Write("{0}) {1}\n", i + 1, numeriPrimi[i]); } Console.Write("Premi un tasto per continuare..."); Console.ReadKey(true); } } class NumeriPrimi { public enum TipoNumero { Primo, Multiplo } static public int[] CrivelloEratostene(int max) { if (max >= 2) { int[] vettNumeri = new int[max - 1]; int cont = vettNumeri.Length; //Inizializzo il vettore supponendo che tutti i numeri siano primi for (int i = 0; i < vettNumeri.Length; i++) { vettNumeri[i] = (int)TipoNumero.Primo; } //Ricerca dei multipli for (int i = 2; i * i <= max; i++) { for (int j = i + i; j <= max; j += i) { if (vettNumeri[j - 2] == (int)TipoNumero.Primo) { vettNumeri[j - 2] = (int)TipoNumero.Multiplo; cont--; } } } //Filtro i primi in un vettore int[] vettPrimi = new int[cont]; cont = 0; for (int i = 0; i < vettNumeri.Length; i++) { if (vettNumeri[i] == (int)TipoNumero.Primo) vettPrimi[cont++] = i + 2; } return vettPrimi; } else return new int[0]; } } }
[modifica] Implementazione in Haskell
crivello :: Int -> [Int] crivello n = f [2 .. n] where f [] = [] f (x:xs) | null xs || x^2 > last xs = (x:xs) | otherwise = x : filter ( (/=0).(`mod`x) ) (f xs)
[modifica] Implementazione in PHP
$n = 1000; $setaccio = array(); //Creo un array di numeri da 2 a N $numeri = range(2,$n); $totnum = count($numeri); while ($totnum>0) { $firstn = array_shift($numeri); $primi[] = $firstn; foreach ($numeri as $value) { if ($value % $firstn == 0) { $setaccio[]=$value; } } if (is_array($setaccio)) { $numeri = array_diff($numeri,$setaccio); } $totnum = count($numeri); unset($setaccio); }; foreach ($primi as $value) { echo $value." "; }
[modifica] Implementazione in Visual basic 6.0
Public Sub NumeriPrimi_Temino89() Dim vett(1 To 10000) As Boolean, Dividendo as Integer, Divisore as Integer Dim Resto as Integer For I = 2 To 10000 Dividendo = I If vett(Dividendo) = False Then For Z = 2 To 10000 Divisore = Z If Dividendo <> Divisore And Divisore > Dividendo Then Resto = Divisore Mod Dividendo If vett(Z) = False Then If Resto = False Then vett(Z) = True Else vett(Z) = False End If End If End If Next Z End If Next I End Sub
[modifica] Implementazione in Java
class Eratostene { public static void main(String[] args) { int i, b; int max = 1000; // Calcola i numeri primi fino a 1000, può essere esteso fino a 10000000 int[] numeri = new int[max]; // Assegna ad ogni elemento del vettore il valore 1 for(i=0; i<max; i++) { numeri[i] = 1; } for(i=2; i<max; i++) { if(numeri[i] == 1) { for(b = i*2; b<max; b += i) // Ciclo per azzerare i multipli di i numeri[b] = 0; } } // Ciclo per stampare tutti gli indici del vettore dove il valore è 1 for(i=2; i<max; i++) { if(numeri[i] == 1) { System.out.println(i); } } } }
[modifica] Implementazione in Ruby
Z=2009 #limite superiore entro cui cercare META=Math.sqrt(Z).to_i #inizializzo l'array con tutti i valori a true criv=[] for i in (1..Z) do criv[i]=true end #crivello for j in (2..META) do b=j+1 for k in (b..Z) do criv[k]=false if k%j==0 end end #visualizzo i risultati puts "Ecco i numeri primi:" for l in (1..Z) do puts l if criv[l] end
[modifica] Voci correlate
Una evoluzione del crivello di Eratostene è rappresentata dal crivello di Atkin, un algoritmo creato circa nel 1999.
[modifica] Altri progetti
Wikiversità contiene informazioni su Il crivello di Eratostene(implementazione in C)


