Eratosthenovo síto je jednoduchý algoritmus pro nalezení všech prvočísel nižších, než je daná horní mez. Tento algorimus je připisován starořeckému učenci Eratosthenovi z Kyrény a je datován cca. do roku 200 př.n.l. Jedná se o jednu z nejefektivnějších metod pro hledání pročísel do . Pro prvočísla vyšší hodnoty je vhodné využít jiných testů
(Rabin-Millerův test, Lehmannův test...).
Princip
Algoritmus se skládá z následujících kroků:
- Napíšeme všechna čísla 2 až n (2 je první prvočíslo). A předpokládáme, že všechna jsou prvočísla.
- Vezmeme si první prvočíslo a víme, že všechny jeho násobky nemohou být z definice prvočísly, proto je vyškrtneme z našeho seznamu.
- Nyní si vezmeme další prvočíslo z proškrtaného seznamu a opět vyházíme všechny jeho násobky.
- Opakujeme 3, dokud nedojdou čísla.
Zlepšení algoritmu: nemá smysl ověřovat všechna čísla, stačí do odmocniny horní meze, protože pokud by horní mez byla složeným číslem (ve tvaru ), tak
nebo
. Z tohoto důvodu, pokud nejvyšší testované číslo není prvočíslem, tak je prověřeno v nejhorším případě při čítání své odmocniny, všechny další testy jsou zbytečné.
Asymptotická složitost
Asymptotická složitost Eratosthenova síta je , kde
je horní mez.
Příklad
Najděte prvočísla do 20.
Vypíšeme si všechna čísla 2-20.
Vyškrtáme násobky dvojky.
Vyškrtáme násobky trojky.
– jsme hotovi.
Kód
/**
* Eratosthenovo sito
* @param upperBound horni mez, prvni cislo, ktere jiz
* nebude vyhodnoceno
*/
public static void sieveOfEratosthenes(int upperBound){
boolean[] sieve = new boolean[upperBound];
//jsme v jave, inicializovano rovnou na false
//true == je slozene
//false == je prvocislo
sieve[0] = sieve[1] = true; //nula a jedna nejsou prvocisla
for(int i = 2; i <= Math.sqrt(sieve.length); i++){
if(sieve[i] == true) continue;
for(int j = 2*i; j < sieve.length; j += i){ //samotne citani
sieve[j] = true; //nemuze byt z definice prvocislem (je nasobkem jineho cisla)
}
}
printSieve(sieve); //na zaver vypiseme prvocisla
}
/**
* Vypise obsah sita
* @param sieve sito true == je slozene, false == je prvocislo
*/
private static void printSieve(boolean[] sieve) {
System.out.println("Prvocisla do cisla " + sieve.length);
for (int i = 2; i < sieve.length; i++) {
if(sieve[i] == false) System.out.print(i + " ");
}
}
/**
* Eratosthenovo sito
* @param upperBound horni mez, prvni cislo, ktere jiz
* nebude vyhodnoceno
*/
void sieveOfEratosthenes(int upperBound){
bool * sieve = new bool[upperBound];
for(int i = 0; i < upperBound; i ++){
sieve[i] = false;
}
//true == je slozene
//false == je prvocislo
sieve[0] = sieve[1] = true; //nula a jedna nejsou prvocisla
for(int i = 2; i <= sqrt((double)upperBound); i++){
if(sieve[i] == true) continue;
for(int j = 2*i; j < upperBound; j += i){ //samotne citani
sieve[j] = true; //nemuze byt z definice prvocislem (je nasobkem jineho cisla)
}
}
printSieve(sieve, upperBound); //na zaver vypiseme prvocisla
delete[] sieve;
}
/**
* Vypise obsah sita
* @param sieve sito true == je slozene, false == je prvocislo
* @param size velikost pole
*/
void printSieve(bool * sieve, int size) {
for (int i = 2; i < size; i++) {
if(sieve[i] == false) cout << i << " ";
}
}