.NET 优化埃拉托色尼 F# 筛法

标签 .net optimization f# sieve-of-eratosthenes f#-interactive

我正在摆弄 F# 并使用 FSI REPL 我注意到我的初学者天真的埃拉托色尼筛法实现的两个略有不同的实现之间存在巨大的效率差异。第一个带有额外的 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 筛 200000 2 [] #time

并且在我的机器上看到,带有额外的 if 语句的实现每次运行大约需要 2 分钟,而没有的则需要大约 1 分钟。 这怎么可能?通过添加处理 3 或 5 的倍数的 if 语句,它实际上比仅映射整个列表然后查找素数列表中是否有数字的约数要慢。 如何? F# 是否针对处理列表进行了优化?

最佳答案

第一个筛子中的额外 if 可能是为了快捷方式,实际上稍微改变了行为。它没有删除除以 3 和 5 的所有内容,而是实际添加了它。比较一下输出就很容易看出:

1st sieve: [19; 17; 15; 13; 11; 9; 7; 5; 3; 2]
2st sieve: [19; 17; 13; 11; 7; 5; 3; 2]

我假设你想要的是这样的:

if (n % 5 = 0) || (n % 3 = 0) then
    sieve max (current + 2) (pList)

但是,在这种情况下,它不会包括 5(很明显)。所以正确的代码是

if (n <> 5 && n % 5 = 0) || (n <> 3 && n % 3 = 0) then
    sieve max (current + 2) (pList)

检查上面代码的性能 - 应该没问题。

关于.NET 优化埃拉托色尼 F# 筛法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49060777/

相关文章:

c# - AesManaged.KeySize 属性的默认值是多少?

iOS UI 自定义优化

python - numpy.transpose 是否在内存中重新排序数据?

f# - 使用 FParsec 解析 int 或 float

f# - `ignore` IDisposable 的正确方法是什么?

c# - 如何让 "Copy to Output Directory"与单元测试一起使用?

C# HttpWebRequest 获取页面总大小

.net - 如何防止新的 WPF 表单窃取焦点?

algorithm - 棘手的谷歌面试问题

c# - 如何将 Serilog.Log.ForContext 与 F# 函数或 C# 方法一起使用