Eratosthenovo síto v C - rychlá implementace
Před pár dny mě inspiroval program na výpis prvočísel od Satíka
Satíkova aplikace generuje poměrně rychle seznam všech prvočísel v řádu přibližně 106. U vyšších hodnot už rychle ztrácí dech, což je celkem pochopitelné a očekávané.
Začal jsem se zajímat, jak rychle lze vygenerovat prvočísla v rozsahu 109?
Napsal jsem tedy základní algoritmus, který využívá naivní implementaci Eratosthenova síta a začal dělat testy. Během pokusů jsem vyzkoušel následující implementace:
- naive Eratosthenes sieve
- segmented Eratosthenes sieve
- wheel factorization
- optimized Eratosthenes sieve
Naivní verze síta je podle očekávání rychlá pouze v rozsahu 106.
Na druhou stranu rozsah 109 je stále ještě směšně malý, takže optimalizace síta za využití segmentace je pouze "kanón na vrabce". I když segmentace přinesla poměrně slušné zrychlení, z hlediska celkového času nepovažuji zisk za odpovídající vůči ceně komplikovaného kódu.
Faktorizace přes "kolo" při velikosti kola 30 také zrychlila běh, ale ani ta nestačila optimalizované verzi algoritmu, pro kterou jsem se nakonec rozhodl zejména kvůli jednoduchosti implementace.
Pokud hledáme prvočísla v rozsahu 3 .. 2*n, připravíme si pole o velikosti n, kde prvek na pozici i reprezentuje hodnotu 2*n+1. Pole inicializujeme na true. Následující kód označí všechna složená čísla v daném rozsahu, zatímco prvočíselné hodnoty zůstanou nezměněny.
// iprime je 64-bitové celé číslo bez znaménka for (iprime i = 1, j = 3; i < n; i++, j += 2) for (iprime k = j * j >> 1; k < n && primes[i]; k += j) primes[k] = 0;
Poté platí, že liché číslo x je prvočíslo, pokud primes[x >> 1] != 0.
Na procesoru Core i5 byly časy běhu algoritmu přibližně následující (nezahrnuje generování výstupního souboru):
- 106 - 0.002s
- 107 - 0.03s
- 108 - 0.51s
- 109 - 5.9s
- 109 - 1.5s při segmentaci síta
Jak rychle lze tedy najít prvočísla až do miliardy? Během několika sekund.
Využitím řady dalších optimalizací je možné získat prvočísla v rozsahu 109 v čase okolo jedné sekundy. Tyto úpravy zahrnují zejména segmentaci síta kombinovanou s úsporným paměťovým modelem spadajícím do L1 a L2 CPU cache. To se ovšem vyplatí až u vyšších hodnot okolo řádu 1012. Na mém kódu se mi líbí jednoduchost spojená se dostačujícím výkonem.
Zdrojový kód v jazyce C je v příloze.
Galerie

Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 271x (625 B)
Aplikace je včetně zdrojových kódů v jazyce C