我正在学习Clojure并且为了更好地处理我的进度,我决定开始用语言解决项目Euler问题(其中一些我已经用C ++和Python解决了)。问题1如下:
如果我们列出10以下的所有自然数,它们是3或3的倍数 5,我们得到3,5,6和9.这些倍数的总和是23。
查找低于1000的3或5的所有倍数的总和。
这是我第一次参加Clojure解决方案:
(defn main1
([n]
(reduce +
(filter
#(or
(= 0 (mod % 3))
(= 0 (mod % 5)))
(range n)))))
然后我查看了我的Python版本的代码,如下所示:
import sys
import operator
from functools import reduce
def main(n=1000):
"""
returns solution up to but excluding n
"""
genexp = (num for num in range(1, n) if ((num % 3 == 0) or (num % 5 == 0)))
total = reduce(operator.add, genexp)
return total
if __name__ == "__main__":
if len(sys.argv) > 1:
print(main(int(sys.argv[1])))
else:
print(main())
忽略我在Python版本中添加的额外CLI-args内容,唯一的主要区别是我在Clojure中使用filter
而不是生成器。我想我也可以在Python中使用filter
,但仅仅为了论证,我使我的Clojure代码更类似于Python代码:
(defn main2
([n]
(reduce + (for [i (range n)
:let [div3 (= 0 (mod i 3))
div5 (= 0 (mod i 5))]
:when (or div3 div5)]
i))))
这让我思考 - 如何对这些功能进行基准比较呢?对于Python来说,这很容易:
$ time python python/p0001.py 10000000
23333331666668
real 0m2.693s
user 0m2.660s
sys 0m0.018s
$ time python python/p0001.py 100000000
2333333316666668
real 0m26.494s
user 0m26.381s
sys 0m0.050s
在合理的时间内(30秒内)达到n=100,000,000
。如何为我的Clojure函数运行类似的测试?我想我必须在运行之前先编译Clojure代码。鉴于Python代码在这里没有JIT编译,这甚至是公平的比较吗?
另一方面,我的Clojure代码(两个版本)是如何惯用的?什么是代码样式的一些好建议?有类似pep8的风格指南吗?甚至是与Clojure版本的pep20一致的东西:“Python的禅宗”?
答案 0 :(得分:6)
内置函数time
适用于第一次剪切:
(time (main1 100000000)) => 2333333316666668
"Elapsed time: 15824.041487 msecs"
您也可以使用the excellent criterium
library
(ns xyz.core
(:require [criterium.core :as cc] ))
(cc/quick-bench (main1 999))
Evaluation count : 3894 in 6 samples of 649 calls.
Execution time mean : 154.680082 µs
Execution time std-deviation : 750.591607 ns
Execution time lower quantile : 153.982498 µs ( 2.5%)
Execution time upper quantile : 155.870826 µs (97.5%)
Overhead used : 7.898724 ns
Found 1 outliers in 6 samples (16.6667 %)
low-severe 1 (16.6667 %)
Variance from outliers : 13.8889 % Variance is moderately inflated by outliers