Я просто немного экспериментировал с (для меня) новым языком программирования: clojure. И я написал довольно наивную «ситовую» реализацию, которую я затем попытался немного оптимизировать.Почему эта простая ситовая реализация медленнее?
Как ни странно, хотя (для меня по крайней мере), новая реализация не быстрее было, но гораздо медленнее ...
Кто-нибудь может пролить некоторый свет в том, почему это так гораздо медленнее?
Я также заинтересован в других советах в том, как улучшить этот алгоритм ...
С наилучшими пожеланиями,
Arnaud Gouder
; naive sieve.
(defn sieve
([max] (sieve max (range 2 max) 2))
([max candidates n]
(if (> (* n n) max)
candidates
(recur max (filter #(or (= % n) (not (= (mod % n) 0))) candidates) (inc n)))))
; Instead of just passing the 'candidates' list, from which I sieve-out the non-primes,
; I also pass a 'primes' list, with the already found primes
; I hoped that this would increase the speed, because:
; - Instead of sieving-out multiples of 'all' numbers, I now only sieve-out the multiples of primes.
; - The filter predicate now becomes simpler.
; However, this code seems to be approx 20x as slow.
; Note: the primes in 'primes' end up reversed, but I don't care (much). Adding a 'reverse' call makes it even slower :-(
(defn sieve2
([max] (sieve2 max() (range 2 max)))
([max primes candidates]
(let [n (first candidates)]
(if (> (* n n) max)
(concat primes candidates)
(recur max (conj primes n) (filter #(not (= (mod % n) 0)) (rest candidates)))))))
; Another attempt to speed things up. Instead of sieving-out multiples of all numbers in the range,
; I want to sieve-out only multiples of primes.. I don't like the '(first (filter ' construct very much...
; It doesn't seem to be faster than 'sieve'.
(defn sieve3
([max] (sieve max (range 2 max) 2))
([max candidates n]
(if (> (* n n) max)
candidates
(let [new_candidates (filter #(or (= % n) (not (= (mod % n) 0))) candidates)]
(recur max new_candidates (first (filter #(> % n) new_candidates)))))))
(time (sieve 10000000))
(time (sieve 10000000))
(time (sieve2 10000000))
(time (sieve2 10000000))
(time (sieve2 10000000))
(time (sieve 10000000)) ; Strange, speeds are very different now... Must be some memory allocation thing caused by running sieve2
(time (sieve 10000000))
(time (sieve3 10000000))
(time (sieve3 10000000))
(time (sieve 10000000))
Я не могу скопировать источник, он усекается на концах строки. – Sergey
Извините за это ... Теперь код должен быть полным. –
Значительное улучшение скорости, вероятно, связано с тем, что JIT-компилятор запускается после нескольких прогонов ..... вам нужно убедиться, что вы запустите любой код, который вы планируете проводить несколько раз, прежде чем на самом деле провести время, чтобы избежать этого эффекта – mikera