2010-12-07 39 views
3

Problème 10 dans le projet Euler. J'y ai vu une discussion, mais seulement pour C.Optimiser le code Haskell en calculant la somme de tous les nombres premiers inférieurs à deux millions

je le code suivant pour calculer:

print . sum . sieve $ [2..2000000] where 
    sieve [] = [] 
    sieve (x:xs) = x : sieve (filter ((/= 0) . (`mod` x)) xs) 

Il faut calculer les âges à. Je me demande s'il existe un moyen plus efficace de le calculer?

+0

Aussi, une faute de frappe: vous avez 'seive' au lieu de' sieve'. –

+0

Mis à jour. Merci Antal. – swcai

+0

Il est possible de le faire en temps sub-linéaire, https://stackoverflow.com/questions/44441627/how-to-optimize-this-haskell-code-summing-up-the-primes. –

Répondre

7

De nombreux moyens très rapides de calculer les nombres premiers en haskell sont décrits sur le haskellwiki page for Prime numbers. Plus précisément, le second semble être assez bon, alors vous pourriez écrire comme ceci:

main = print . sum . takeWhile (< 2000000) $ primes 

primes = 2: 3: sieve (tail primes) [5,7..] 

sieve (p:ps) xs = h ++ sieve ps [x | x <- t, rem x p /= 0] 
    where (h,~(_:t)) = span (< p*p) xs 

Son exécution, nous obtenons:

ghc --make -O2 Euler10.hs 
time ./SOAns 
142913828922 

real 0m1.598s 
user 0m1.577s 
sys 0m0.017s 

Le wiki décrit pourquoi votre solution est si lent, la raison principale est qu'un tamis est mis en place pour chaque nombre jusqu'à 2000000, quand un pour chaque premier est suffisant.

6

Vous pouvez trouver this paper et la discussion qui s'ensuit intéressante. L'essentiel est que votre implémentation sieve n'est pas aussi efficace que le véritable tamis d'Eratosthène.

+0

bosmacs et HaskellElephant, merci beaucoup. C'est très utile. – swcai

+0

* tamis *. je avant e. – wnoise

+0

Corrigé; Je référençais l'orthographe de la fonction d'origine. – bosmacs

0

Le propre optimisé premier code tamiser J'ai personnellement vu dans Haskell est dans le paquet NumberSieves, qui comprend à la fois un tamis traditionnelle à base de vecteurs mutables et une forme de tamis de O'Neill. N'utilisez pas le code horriblement complexe dans le package arithmoi: au moins une partie de ce code est actuellement interrompue et produit de manière aléatoire des erreurs de segmentation.