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.

Indice

[modifica] Algoritmo

Animazione del crivello

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: a = p \times r con \,\!r > p.

Se ne deduce che a = p \times r \ge p \times p = p^2 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

Strumenti personali