Crivello di Eratostene

algoritmo per trovare i numeri primi

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.

Animazione del crivello
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 intero 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.

Algoritmo

#!/bin/bash
# sieve.sh

# Crivello di Eratostene
# di Stephane Chazelas

#  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
/* Copyright Emanuele Piccolini - Codice sotto GNU/GPLv2 - Si deve invocare con un argomento da linea di comando. */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void Eratostene(int *array,int upperbound);

int main(int argc, char **argv)
{
	int upperbound,i;
	int *array=NULL;

	if(argc<2) return 0;

	/* Copia Upperbound */
	upperbound = atoi(argv[1]);

	if(upperbound > 0){
		/* Allocazione e Popolamento dell'Array */
		array = (int *) malloc(upperbound * sizeof(int) );
		for(i=0;i<upperbound;i++) array[i] = (i+1);

		/* Crivello di Eratostene */
		Eratostene(array,upperbound);
	
		/* Stampa degli elementi rimasti, ovvero i primi */
		for(i=0;i<upperbound;i++) if(array[i] != -1) printf("%d ",array[i]);
		printf("\n");
	
		/* Distruzione dell'Array */
		free(array);
		array = NULL;
	}

	return 0;
}

void Eratostene(int *array,int upperbound){

	int pi,i;

	/* Creazione Array Perno */
	int * perni = malloc(((int)sqrt(upperbound))*sizeof(int));

	/* Popolamento array perno */
	for(i=0;i<((int)sqrt(upperbound));i++) perni[i] = (i+1);

	/* Cancellazione Multipli dei perni */
	for(pi=1;pi<((int)sqrt(upperbound));pi++){
		for(i=0;i<upperbound;i++) if(((array[i]%perni[pi])==0) && (array[i] != perni[pi])) array[i] = -1;
	}

	free(perni);

	return;

}

Altro metodo

#include <stdio.h>
#include <conio.h>
#define SIZE 1000

int main()
{
	/*Dichiaro il vettore di SIZE dimensione 	*/
	int numeri[SIZE];
	int a,b;

	/*Inizializzo ad 1 ogni elemento*/
	for(a=0;a<SIZE;a++)
		numeri[a]=1;

	/*Scorro i numeri dal 2 fino a SIZE*/
	for(a=2;a<SIZE;a++)
                   /*fracca cula*/
		/*Se il vettore nella posizione [a] è uguale ad 1*/
		if(numeri[a]==1)
			/*eseguo un ciclo da [a+a] fino a SIZE*/
			for(b=a+a;b<SIZE;b+=a)
				/*e azzero ogni elemento multiplo di a*/
				numeri[b]=0;

	/*Outputo i numeri primi che hanno nel vettore il valore 1*/
	for(a=2;a<SIZE;a++)
		if(numeri[a]==1)
			printf("%d \n",a);

	getchar();
        getch();
	return 0;
}
function crivella($size=1000){
	//Dichiaro le variabili
	$a=$b=0;

	//Riempio il vettore da 0 a 1000 con il valore 1
	$numeri=array_fill(0, $size, 1);

	//Scorro i numeri dal 2 fino a $size
	for($a=2;$a<$size;$a++){
		//Se il vettore nella posizione [$a] è uguale ad 1
		if($numeri[$a]==1){
			//eseguo un ciclo da [$a+$a] fino a $size
			for($b=$a+$a;$b<$size;$b+=$a)
				//e azzero ogni elemento multiplo di a
				$numeri[$b]=0;
		}
	}

	//Output dei numeri primi che hanno nel vettore il valore 1
	for($a=2;$a<$size;$a++){
		if($numeri[$a]==1)
			echo "$a\n";
	}
}

Voci correlate

Una evoluzione del crivello di Eratostene è rappresentata dal crivello di Atkin, un algoritmo creato circa nel 1999.