Euler 23 在 C# 中:0.2 秒,在 F# 中:30.5 秒。为什么?

2023-12-03

我对这个问题的 F# 解决方案不太满意,因为我找不到一个漂亮且快速的解决方案,但这不是这里的问题。问题是,我将解决方案翻译成 C#,而且速度很快。就像,相对而言,速度非常快。

我不明白为什么。是的,我去过 Reflector,C# 代码看起来很相似,不能说我真的理解 IL,但看起来有点像。我唯一能想到的是 F# int[] 相对于 C# List 的性能。

所以事情是这样的:

F#

module Euler023

let divisorsSum n =
  let mutable sum = 1
  let limit = (int (sqrt(float n)))
  for i in [2..limit] do
    if n%i=0 then sum <- sum+i+n/i
  if (limit*limit)=n then sum-limit else sum

let isAbundant x = (divisorsSum x)>x
let abundants  = [1..28123] |> List.filter isAbundant |> List.toArray
let domain = System.Collections.BitArray(28124)

let rec loopUntil i j =
    if i=abundants.Length then ()
    elif j=abundants.Length then loopUntil (i+1) (i+1)
    else
      let sum = abundants.[i]+abundants.[j] 
      if sum<28124 then 
        domain.Set(sum, true)
        loopUntil i (j+1)
      else 
        loopUntil (i+1) (i+1)

let solve  =    loopUntil 0 0
            [1..28123] |> List.filter (fun x -> domain.Get(x)=false) |> List.sum

C#

static int divisorsSum(int n)
{
    int sum = 0;
    var limit = (int)Math.Sqrt(n);

    for (int i=2;i<=limit;++i) if (n%i==0) sum += i + n/i;

    if ((limit * limit) == n) return sum-limit;

    return sum;
}

static List<int> getAbundants(int ceiling)
{
    var ret = new List<int>();

    for (int i = 1; i < ceiling; ++i) if (divisorsSum(i) > i) ret.Add(i);

    return ret;
}

 static void Main(string[] args)
 {

     var abundants = getAbundants(28124);
     var bitField = new bool[28124];

     for (int i = 0; i < abundants.Count; ++i)
         for (int j = i; j < abundants.Count; ++j)
         {
             var sum = abundants[i] + abundants[j];
             if (sum < 28124) bitField[sum] = true;
             else break;
         }

     var total = 0;
     for (int i = 0; i < 28124; ++i) if (bitField[i]==false) total += i;

}

Update

包含此代码的项目由每个问题的单独文件 (EulerXXX.fs) + 主程序文件组成。主程序文件如下

module Program =


let stopWatch = System.Diagnostics.Stopwatch()
let mutable totalTime = System.TimeSpan()

let inline tick()
 = 
    stopWatch.Stop();
    totalTime <- totalTime.Add stopWatch.Elapsed
    printfn " -> Elapsed: %2.2f sec Total: %2.2f s" stopWatch.Elapsed.TotalSeconds  totalTime.TotalSeconds
    stopWatch.Restart()

let _ = 

    stopWatch.Start()
    printf "Euler001 solution: %A" Euler001.solve
    tick()
    printf "Euler002 solution: %A" Euler002.solve
    tick()
    printf "Euler003 solution: %A" Euler003.solve
    tick()
    printf "Euler004 solution: %A" Euler004.solve
    tick()
    printf "Euler005 solution: %A" Euler005.solve
    tick()
    printf "Euler006 solution: %A" Euler006.solve
    tick()
    printf "Euler007 solution: %A" Euler007.solve
    tick()
    printf "Euler008 solution: %A" Euler008.solve
    tick()
    printf "Euler009 solution: %A" Euler009.solve
    tick()
    printf "Euler010 solution: %A" Euler010.solve
    tick()
    printf "Euler011 solution: %A" Euler011.solve
    tick()
    printf "Euler012 solution: %A" Euler012.solve
    tick()
    printf "Euler013 solution: %A" Euler013.solve
    tick()
    printf "Euler014 solution: %A" Euler014.solve
    tick()
    printf "Euler015 solution: %A" Euler015.solve
    tick()
    printf "Euler016 solution: %A" Euler016.solve
    tick()
    printf "Euler017 solution: %A" Euler017.solve
    tick()
    printf "Euler018 solution: %A" Euler018.solve
    tick()
    printf "Euler019 solution: %A" Euler019.solve
    tick()
    printf "Euler020 solution: %A" Euler020.solve
    tick()
    printf "Euler021 solution: %A" Euler021.solve
    tick()
    printf "Euler022 solution: %A" Euler022.solve
    tick()
    printf "Euler023 solution: %A" Euler023.solve
    tick()
    printf "Euler024 solution: %A" Euler024.solve
    tick()
    printf "Euler059 solution: %A" Euler059.solve
    tick()
    printf "Euler067 solution: %A" Euler067.solve
    tick()
    stopWatch.Stop()
    System.Console.ReadLine()

程序的输出如下:

Euler001 solution: 233168 -> Elapsed: 0.02 sec Total: 0.02 s
Euler002 solution: 4613732 -> Elapsed: 0.03 sec Total: 0.04 s
...
Euler022 solution: 871198282 -> Elapsed: 0.02 sec Total: 4.11 s
Euler023 solution: 4179871 -> Elapsed: 81.11 sec Total: 85.22 s
Euler024 solution: [2; 7; 8; 3; 9; 1; 5; 4; 6; 0] -> Elapsed: 0.01 sec Total: 85.23 s
...
Euler067 solution: [7273] -> Elapsed: 0.01 sec Total: 85.31 s

所以问题不在于项目参数。另外,如果我将代码从 Euler023 复制到 Program ,它将立即运行。 问题是,为什么只有这个问题才会出现这种放缓?


你的 F# 版本一点也不慢;在我的机器上,F# Interactive 需要 0.44 秒。我不知道你怎么能观察到这么慢(30.5 秒)。如果编译并运行代码,请确保处于发布模式并打开优化和尾调用消除。

但是,您仍然可以通过消除冗余中间集合的使用来进一步优化。

A. 变更(冗余)清单[2..limit]范围表达式2..limit in divisorsSum:

for i in 2..limit do
    if n%i=0 then sum <- sum+i+n/i

B. 生成丰度数组而不创建大列表(更忠实于 C# 版本):

let abundants = 
    let arr = ResizeArray(28123)
    for i in 1..28123 do
        if isAbundant i then arr.Add i
    arr.ToArray()

C、计算solve无需创建大列表:

let solve = 
    loopUntil 0 0
    let mutable sum = 0
    for i in 1..28123 do
       if not <| domain.Get(i) then
            sum <- sum + i
    sum

新的 F# 版本比原始版本快 4 倍;大约需要0.1秒才能完成。

UPDATE:

你的测量不准确。首先,您测量了两次打印值调用之间的时间差。第二,EulerXXX.solve是价值观;因此它们是在编译程序时预先计算的。你应该声明EulerXXX.solve作为函数:

let solve() = ...

并测量函数调用的执行时间:

let time fn =
    let sw = new System.Diagnostics.Stopwatch()
    sw.Start()
    let f = fn()
    sw.Stop()
    printfn "Time taken: %.2f s" <| (float sw.ElapsedMilliseconds)/1000.0
    f

let s023 = time Euler023.solve
printf "Euler023 solution: %A" s023
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Euler 23 在 C# 中:0.2 秒,在 F# 中:30.5 秒。为什么? 的相关文章

随机推荐

  • 如何将一个字符串哈希为8位数字?

    无论如何 我可以将随机字符串哈希为 8 位数字 而无需自己实现任何算法吗 是的 您可以使用内置的hashlib模块或内置hash功能 然后 对哈希的整数形式使用模运算或字符串切片运算截取最后八位数字 gt gt gt s she sells
  • $_SERVER["HTTP_REFERER"] 无法在 Mozilla 上运行

    我开发了一个简单的模态框并添加了 SERVER HTTP REFERER 所以从特定的引荐来源网址到不会出现 它工作正常 但是 SERVER HTTP REFERER 不适用于 Mozilla 还有其他方法可以做到这一点吗 我正在使用简单的
  • 读取输入后隐藏控制台窗口

    我有一个带有 GUI 的脚本 它获取用户数据并将其存储到文本文件中 它运行另一个脚本 exe 等待用户输入 然后执行一些工作 我想要的是后一个脚本在读取用户的输入后隐藏其控制台窗口 但继续在后台工作 我尝试运行该脚本subprocess c
  • 基于另一列值的一列的累积和 (R)

    我有一个包含 2 列的数据框 如下所示 gt data frame x 1 10 y c 0 0 0 1 1 0 0 1 0 1 x y 1 1 0 2 2 0 3 3 0 4 4 1 5 5 1 6 6 0 7 7 0 8 8 1 9 9
  • 存储信用卡详细信息

    我的业务要求迫使我在短时间内存储客户的完整信用卡详细信息 号码 姓名 到期日 CVV2 理由 如果客户打电话订购产品 而他们的信用卡当场被拒绝 您很可能会失去销售机会 如果您获取他们的详细信息 感谢他们的交易 然后发现该卡被拒绝 您可以给他
  • 如何搜索可用的 RFC 功能模块和表

    我必须承认我不是 SAP R 3 编程方面的专家 所以这更多的是关于这个问题的基本问题 有没有办法获取 SAP 系统上可访问的 RFC 模块和 或表的列表 在互联网上的许多示例中 我发现一个 RFC 模块似乎在每个 SAP 系统上都可用 S
  • 查找所有重叠区间的计数

    我有所有记录的开始时间和结束时间 如下所示 startTime 21345678 endTime 31345678 我正在尝试查找所有冲突的数量 例如 如果有两条记录并且它们重叠 则冲突数为 1 如果有 3 个记录 其中两条重叠 则冲突为
  • 禁用按钮/禁用选项菜单的 tkinter 颜色

    我正在为 Unity Ubuntu 开发一个快速列表编辑器 初始 界面包含禁用的选项菜单按钮 右下的 和编辑按钮 右上角 和禁用的 正常 按钮 然而 tkinter 并不同等对待这两种禁用图标 禁用的选项菜单图标比 正常 禁用按钮图标稍暗
  • 如何标记视频播放器以从其他应用程序打开视频文件?

    我写了一个视频播放器 想知道 当您从其他应用程序 例如文件浏览器 单击视频文件时 会出现可以打开该视频文件的应用程序列表 如何让我的玩家也出现在该列表中 Thanks 您必须注册Intent你想要在你的活动中 从 API 15 开始 您需要
  • Xcode PhoneGap navigator.connection 未定义

    尝试将我的 PhoneGap javascript 代码移植到 Xcode 中以便在 iOS 中进行调试 使用 Cordova 3 0 0 当我打电话时 navigator connection type 我收到 navigator con
  • 在哪里可以获得 BERT 的预训练词嵌入?

    我知道 BERT 的总词汇量为 30522 其中包含一些单词和子词 我想获得 BERT 的初始输入嵌入 所以 我的要求是获得尺寸表 30522 768 我可以通过 token id 进行索引来获取其嵌入 我在哪里可以得到这张桌子 BertM
  • gl_PointSize、gl_Position、gl_FragCoord之间的关系

    例子 VS 着色器 void main gl Position vec4 0 0 0 1 gl PointSize 100 0 画布为 1x5 像素 宽度 高度 片段着色器使用 gl FragCoord 这 5 个像素的 gl FragCo
  • 从活动类中打开 Android 导航抽屉

    我正在开发安卓系统Navigation Drawer通过他们的文档看起来 抽屉只能扩展 Fragment Activity 因此要从我的所有活动中打开抽屉 我需要将我的所有活动变成一个片段 这不是一个可行的解决方案 有没有办法打开一个从 A
  • 如何在删除 SQLite 数据库中的行后更新 KEY_ROWID

    从数据库中删除一行后 如何更新 SQLite 数据库中的 KEY ROWID 编号 情况1 例如 如果我的数据库中有五行 则此时 KEY ROWID 的最大值为 5 我删除表中的所有行 然后我添加新行 此时KEY ROWID不再从1开始 它
  • Terraform 从 Packer 中创建的托管磁盘映像创建 VM

    我已经使用 Packer 创建了一个自定义 VM 映像 现在我尝试使用 Terraform 基于此映像创建一个新 VM 但我对如何设置 TF 文件感到困惑 我可以创建其余的基础设施 我认为我的打包器 json 文件创建了一个托管磁盘映像 但
  • Objective-c 中的 AES256 解密问题

    我正在尝试使用以下代码片段来解密文件 该文件是使用 32 字节密钥加密的 因此 当我尝试加密文件数据时 一切正常 但是当我尝试解密时 程序甚至没有通过条件if cryptStatus kCCSuccess 在 CryptoExtension
  • 使用 Visual Studio 或 TFS 在项目之间共享资源(图像/css/js)

    有没有一种有效的方法可以在不同项目之间共享视觉资源 这包括图像 CSS 和 JavaScript 我查看了以下 Stack Overflow 问题 但似乎没有回答这个问题 在 Visual Studio 中的不同项目之间共享 css jav
  • 突出显示一行时是否触发任何事件?

    我创建了一个 ListView 来显示文档列表 然后创建了一个按钮 按钮 A 来执行一些操作 我的要求是我希望按钮状态可以随着所选文档的更改而更改 Fox示例 下图中有三个文档 我希望当我单击Order 00001或Order 00002时
  • 仅从文件的完整路径获取文件名

    我想分割路径 只保存文件名test xls在一个新变量中 namearray C Users z003m Desktop Service Tickets automationscript vbs Newfolder test xls 推荐使
  • Euler 23 在 C# 中:0.2 秒,在 F# 中:30.5 秒。为什么?

    我对这个问题的 F 解决方案不太满意 因为我找不到一个漂亮且快速的解决方案 但这不是这里的问题 问题是 我将解决方案翻译成 C 而且速度很快 就像 相对而言 速度非常快 我不明白为什么 是的 我去过 Reflector C 代码看起来很相似