C# 为什么F代码比C代码慢?

C# 为什么F代码比C代码慢?,c#,f#,C#,F#,我正在再次处理Euler项目的问题(在我学习C#时做过前23个问题),我对我的问题5解决方案表现不佳感到困惑 内容如下: 2520是可以被每个数字除的最小数字 从1到10,没有任何余数 能被全部整除的最小正数是多少 从1到20的数字是多少 现在,我难以置信的原始蛮力解决方案C#在大约25秒内解决了这个问题 var numbers = Enumerable.Range(1, 20); int start = 1; int result; while (true) { if (numbers.

我正在再次处理Euler项目的问题(在我学习C#时做过前23个问题),我对我的问题5解决方案表现不佳感到困惑

内容如下:

2520是可以被每个数字除的最小数字 从1到10,没有任何余数

能被全部整除的最小正数是多少 从1到20的数字是多少

现在,我难以置信的原始蛮力解决方案C#在大约25秒内解决了这个问题

var numbers = Enumerable.Range(1, 20);
int start = 1;
int result;
while (true)
{
   if (numbers.All(n => start % n == 0))
   {
       result = start;
       break;
   }
   start++;
}
现在,我的F#解决方案也使用了暴力强迫,但至少它有更多的辨别力,所以在我看来,它“应该”运行得更快,但它以45秒左右的时钟停止,所以它的速度几乎是C#1的两倍


我知道我的解决方案可能会更好,在这种情况下,我只是想知道,一个更好的暴力解决方案怎么会比原始解决方案慢这么多。

好吧,一定是这一点

            divisors |> Seq.takeWhile(fun x -> n % x = 0)                
    Seq.length dividesBy = Seq.length divisors

我认为您可以将其重写为一个更简单的递归函数,它将更类似于您最初的c#实现

您可以使用
List.forall
而不是转换为seq,然后执行
seq.length

let divisors = [3..20] |> List.rev
let isDivOneToTwenty n = divisors |> List.forall (fun d -> n % d = 0)
Seq.length
将需要遍历整个序列以确定元素的数量,而
forall
可以在元素未通过谓词时立即返回

您还可以将
findNum
编写为:

let rec findNum n = if isDivOneToTwenty n then n else findNum (n + 2)

甚至更直接的翻译,如

let numbers = { 1..20 }
let rec loop start =
    if numbers |> Seq.forall (fun n -> start % n = 0) 
    then start
    else loop (start + 1)
loop 1
需要一分半钟(你的C#版本在我的机器上也需要25秒)。数字序列似乎是罪魁祸首,因为它将其更改为数组(
[|1..20 |]
)并使用
数组。因为所有的
都会将其降低到8秒。使用数组的C#版本需要20秒(使用我自己的数组专用的
ForAll
方法而不是
Enumerable.All
需要17秒)


编辑:在看到李的答案后,我尝试了
列表。对于所有的
,它甚至比数组快(~5秒)。

就是它。实际上,在我的测试中,
List.forall
Seq.forall
相比有很大的不同。就像100秒对10秒。@mikez-Yes
takeWhile
会提前中断,每次都会将该计数与整个除数序列的长度进行比较,因此每次调用时它都会遍历一到两次。是的,我在写完我的评论后就意识到了这一点,所以我删除了它。+1。这个简单的更改将我的机器的运行时间减少到2,5秒左右。这正是我想要的。请注意,解决方案也必须是2520的倍数。因此,您的增量可以是2520,您将测试的数字要少得多。即使有一个简单的暴力解决方案,它也会很快实现。另外,你不需要测试1到10的可除性。这不是一个完全相同的。但这也解释了为什么F#现在真的比C#@L.B慢?你要来这里对演出说粗话吗?我从未声称这是一个特别好的解决方案。不是每个人天生都有很好的编码天赋,也许这就是我为什么要学习的原因?
let numbers = { 1..20 }
let rec loop start =
    if numbers |> Seq.forall (fun n -> start % n = 0) 
    then start
    else loop (start + 1)
loop 1