Przede wszystkim mod
jest powolny więc używać rem
w sytuacjach, w których nie ma znaczenia (gdy nie mamy do czynienia z negatywów, w zasadzie). Po drugie, użyj Criterion, aby pokazać (samemu), co jest szybsze, a jakie zmiany są faktycznie optymalizacjami. Wiem, że nie daję pełną odpowiedź, że pytanie o to, ale jest to dobre miejsce dla ciebie (i inni potencjalni Główni odpowiadający), aby rozpocząć, więc tutaj jest jakiś kod:
import List
import Criterion.Main
main = do
str <- getLine
let run f = length . f
input = read str :: Integer
defaultMain [ bench "primes" (nf (run primes) input)
, bench "primes'" (nf (run primes') input)
, bench "primes''" (nf (run primes'') input)
, bench "primesTMD" (nf (run primesTMD) input)
, bench "primes'TMD" (nf (run primes'TMD) input)
, bench "primes''TMD" (nf (run primes''TMD) input)
]
putStrLn . show . length . primes'' $ (read str :: Integer)
-- primeira implementação
primes n
| n < 2 = []
| n == 2 = [2]
| n `mod` 2 == 0 = primes'
| otherwise = if (find (\x -> n `mod` x == 0) primes') == Nothing then
n:primes'
else
primes'
where primes' = primes (n - 1)
primesTMD n
| n < 2 = []
| n == 2 = [2]
| n `mod` 2 == 0 = primes'
| otherwise = if (find (\x -> n `rem` x == 0) primes') == Nothing then
n:primes'
else
primes'
where primes' = primesTMD (n - 1)
-- segunda implementação
primes' :: Integer -> [Integer]
primes' n = sieve $ 2 : [3,5..n]
where sieve :: [Integer] -> [Integer]
sieve [] = []
sieve [email protected](x:xs)
| x*x >= n = l
| otherwise = x : sieve list'
where list' = filter (\y -> y `mod` x /= 0) xs
primes'TMD :: Integer -> [Integer]
primes'TMD n = sieve $ 2 : [3,5..n]
where sieve :: [Integer] -> [Integer]
sieve [] = []
sieve [email protected](x:xs)
| x*x >= n = l
| otherwise = x : sieve list'
where list' = filter (\y -> y `rem` x /= 0) xs
-- terceira implementação
primes'' :: Integer -> [Integer]
primes'' n = 2 : sieve 3 [3,5..n]
where sieve :: Integer -> [Integer] -> [Integer]
sieve _ [] = []
sieve m [email protected](x:xs)
| m*m >= n = l
| x < m*m = x : sieve m xs
| otherwise = sieve (m + 2) list'
where list'= filter (\y -> y `mod` m /= 0) l
primes''TMD :: Integer -> [Integer]
primes''TMD n = 2 : sieve 3 [3,5..n]
where sieve :: Integer -> [Integer] -> [Integer]
sieve _ [] = []
sieve m [email protected](x:xs)
| m*m >= n = l
| x < m*m = x : sieve m xs
| otherwise = sieve (m + 2) list'
where list'= filter (\y -> y `rem` m /= 0) l
Wskazówka ulepszona runtime warianty użyciu rem
:
$ ghc --make -O2 sieve.hs
$./sieve
5000
...
benchmarking primes
mean: 23.88546 ms, lb 23.84035 ms, ub 23.95000 ms
benchmarking primes'
mean: 775.9981 us, lb 775.4639 us, ub 776.7081 us
benchmarking primes''
mean: 837.7901 us, lb 836.7824 us, ub 839.0260 us
benchmarking primesTMD
mean: 16.15421 ms, lb 16.11955 ms, ub 16.19202 ms
benchmarking primes'TMD
mean: 568.9857 us, lb 568.5819 us, ub 569.4641 us
benchmarking primes''TMD
mean: 642.5665 us, lb 642.0495 us, ub 643.4105 us
Chociaż widzę, robisz to na własną edukację, warto zauważyć związane z nimi więzi Primes on Haskell.org i szybki Primes package na hackage.
1) Twój angielski jest w porządku. 2) Naprawdę podoba mi się, że dołączasz działający kod - tak niewiele pytań robi ostatnio. 3) Możesz również dołączyć polecenie kompilacji - niektórzy zapominają -O2 (i dawno temu eksperymentalny -O3 istniał i spowalniał wiele programów, ale nowi użytkownicy nie wiedzieli o tym). –
Może Cię zainteresować artykuł [The Genuine Sieve of Eratosthenes] (http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf). Obejmuje kilka różnych implementacji (w tym fałszywe sito) i omawia podstawowe cechy wydajności, a także oferuje kilka sposobów przyspieszenia algorytmu. –
Jedną z ważnych wiadomości z artykułu "Oryginalna sito Eratostenesa" jest to, że chociaż kody takie jak te trzy są często dostarczane jako "implementacje sita Eratostenesa", ich wydajność jest bliższa algorytmowi dzielenia prób (powoli) niż sita Eratostenesa (szybko). –