gpt4 book ai didi

python - 为什么对于 Euler 50 的等效解决方案,Clojure 比 Python 慢 10 倍?

转载 作者:太空狗 更新时间:2023-10-29 17:05:37 25 4
gpt4 key购买 nike

我最近开始学习 Clojure 并决定练习欧拉问题以掌握可用的数据结构并练习递归和循环。

我尝试了各种方法来 Problem 50 ,但无论我做什么,找到 1000000 的解决方案从未完成。在我查阅了其他人的做法后,我猜我所做的应该也不会花很长时间,所以我在 Python 中输入了等效的算法,看看问题是否出在我对某些 Clojure 的东西或 Java 设置缺乏理解。 Python 在 10 秒内完成。对于 100000 以下的素数,Python 版本在 0.5 秒内完成,Clojure 在 5 秒内完成。

我发布的是专门为匹配 Python 代码而创建的 Clojure 版本。你能帮我理解为什么会有这样的性能差异吗?我应该使用未经检查的添加、类型提示、基元(但在哪里?)还是什么?

这是 Clojure:

(defn prime? [n]
(let [r (int (Math/sqrt n))]
(loop [d 2]
(cond
(= n 1) false
(> d r) true
(zero? (rem n d)) false
:other (recur (inc d))))))

(defn primes []
(filter prime? (iterate inc 2)))


(defn cumulative-sum [s]
(reduce
(fn [v, x] (conj v (+ (last v) x)))
[(first s)]
(rest s)))


(defn longest-seq-under [n]
"Longest prime seq with sum under n"
(let [ps (vec (take-while #(< % n) (primes))) ; prime numbers up to n
prime-set (set ps) ; set for testing of inclusion
cs (cumulative-sum ps)
cnt (count ps)
max-len (count (take-while #(< % n) cs)) ; cannot have longer sequences
sub-sum (fn [i j] ; sum of primes between the i-th and j-th
(- (cs j) (get cs (dec i) 0)))
seq-with-len (fn [m] ; try m length prime sequences and return the first where the sum is prime
(loop [i 0] ; try with the lowest sum
(if (> i (- cnt m)) ; there are no more elements for and m length sequence
nil ; could not find any
(let [j (+ i (dec m)) ; fix length
s (sub-sum i j)]
(if (>= s n) ; overshoot
nil
(if (prime-set s) ; sum is prime
[i (inc j)] ; we just looked for the first
(recur (inc i))))))))] ; shift window
(loop [m max-len] ; try with the longest sequence
(if (not (zero? m))
(let [[i j] (seq-with-len m) ]
(if j
(subvec ps i j)
(recur (dec m))))))))



(assert (= [2 3 5 7 11 13] (longest-seq-under 100)))

(let [s1000 (longest-seq-under 1000)]
(assert (= 21 (count s1000)))
(assert (= 953 (reduce + s1000))))

; (time (reduce + (longest-seq-under 100000))) ; "Elapsed time: 5707.784369 msecs"

在 Python 中也是如此:

from math import sqrt
from itertools import takewhile

def is_prime(n) :
for i in xrange(2, int(sqrt(n))+1) :
if n % i == 0 :
return False
return True

def next_prime(n):
while not is_prime(n) :
n += 1
return n

def primes() :
i = 1
while True :
i = next_prime(i+1)
yield i

def cumulative_sum(s):
cs = []
css = 0
for si in s :
css += si
cs.append( css )
return cs


def longest_seq_under(n) :
ps = list(takewhile( lambda p : p < n, primes()))
pss = set(ps)
cs = cumulative_sum(ps)
cnt = len(ps)
max_len = len(list(takewhile(lambda s : s < n, cs)))

def subsum(i, j):
return cs[j] - (cs[i-1] if i > 0 else 0)

def interval_with_length(m) :
for i in xrange(0, cnt-m+1) :
j = i + m - 1
sij = subsum(i,j)
if sij >= n :
return None, None
if sij in pss : # prime
return i, j+1
return None, None

for m in xrange(max_len, 0, -1) :
f, t = interval_with_length(m)
if t :
return ps[f:t]


assert longest_seq_under(100) == [2, 3, 5, 7, 11, 13]
assert sum(longest_seq_under(1000)) == 953

# import timeit
# timeit.Timer("sum(longest_seq_under(100000))", "from __main__ import longest_seq_under").timeit(1) # 0.51235757617223499

谢谢

最佳答案

我认为速度变慢是因为您遍历 longest-seq-under 中的序列的次数;每一次迭代都会付出代价。这是一个吸烟快速版本,基于您的代码和发布的答案的组合 here .注意 primes 是惰性的,所以我们可以用 defdefn 绑定(bind)它:

(defn prime? [n]
(let [r (int (Math/sqrt n))]
(loop [d 2]
(cond (= n 1) false
(> d r) true
(zero? (rem n d)) false
:else (recur (inc d))))))

(def primes (filter prime? (iterate inc 2)))

(defn make-seq-accumulator
[[x & xs]]
(map first (iterate
(fn [[sum [s & more]]]
[(+ sum s) more])
[x xs])))

(def prime-sums
(conj (make-seq-accumulator primes) 0))

(defn euler-50 [goal]
(loop [c 1]
(let [bots (reverse (take c prime-sums))
tops (take c (reverse (take-while #(> goal (- % (last bots)))
(rest prime-sums))))]
(or (some #(when (prime? %) %)
(map - tops bots))
(recur (inc c))))))

这在我的机器上用了大约 6 毫秒完成:

user> (time (euler-50 1000000))
"Elapsed time: 6.29 msecs"
997651

关于python - 为什么对于 Euler 50 的等效解决方案,Clojure 比 Python 慢 10 倍?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8064336/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com