【发布时间】:2018-08-10 04:12:51
【问题描述】:
我正在摆弄 F# 并使用 FSI REPL,我注意到在我的初学者的幼稚 Eratosthenes 实现的两个略有不同的实现之间存在巨大的效率差异。第一个带有额外的 if:
let rec sieve max current pList =
match current with
| 2 -> sieve max (current + 1) (current::pList)
| 3 -> sieve max (current + 2) (current::pList)
| n when n < max ->
if (n % 5 = 0) || (n % 3 = 0) then
sieve max (current + 2) (current::pList)
else if (pList |> (List.map (fun n -> current % n = 0)) |> List.contains true) then
sieve max (current + 2) (pList)
else
sieve max (current + 2) (current::pList)
| n when n >= max
-> pList
| _
-> printfn "Error: list length: %A, current: %A" (List.length pList) current
[-1]
第二个没有:
let rec sieve max current pList =
match current with
| 2 -> sieve max (current + 1) (current::pList)
| 3 -> sieve max (current + 2) (current::pList)
| n when n < max ->
if (pList |> (List.map (fun n -> current % n = 0)) |> List.contains true) then
sieve max (current + 2) (pList)
else
sieve max (current + 2) (current::pList)
| n when n >= max
-> pList
| _
-> printfn "Error: list length: %A, current: %A" (List.length pList) current
[-1]
具有额外if 分支的分支实际上更慢,尽管它看起来应该会更快。
然后,我使用以下方法对 REPL 中的两个实现进行计时:
#time
sieve 200000 2 []
#time
并在我的机器上看到,带有额外 if 语句的实现大约需要 2 分钟,而没有的实现每次运行大约需要 1 分钟。
这怎么可能?通过添加处理 3 或 5 的倍数的 if 语句,它实际上比仅映射整个列表然后查找素数列表中是否有任何数字的除数要慢。
如何? 仅仅是 F# 对处理列表进行了优化吗?
【问题讨论】:
标签: .net optimization f# sieve-of-eratosthenes f#-interactive