编程语言
首页 > 编程语言> > 与Project Euler的速度比较:C vs Python vs Erlang vs Haskell

与Project Euler的速度比较:C vs Python vs Erlang vs Haskell

作者:互联网

我从Project Euler开始将Problem #12作为编程练习并比较我在C,Python,Erlang和Haskell中的(当然不是最优的)实现.为了获得更高的执行时间,我搜索第一个三角形数字,其中有超过1000个除数而不是原始问题中所述的500.

结果如下:

C:

lorenzo@enzo:~/erlang$gcc -lm -o euler12.bin euler12.c
lorenzo@enzo:~/erlang$time ./euler12.bin
842161320

real    0m11.074s
user    0m11.070s
sys 0m0.000s

Python:

lorenzo@enzo:~/erlang$time ./euler12.py 
842161320

real    1m16.632s
user    1m16.370s
sys 0m0.250s

Python与PyPy:

lorenzo@enzo:~/Downloads/pypy-c-jit-43780-b590cf6de419-linux64/bin$time ./pypy /home/lorenzo/erlang/euler12.py 
842161320

real    0m13.082s
user    0m13.050s
sys 0m0.020s

二郎:

lorenzo@enzo:~/erlang$erlc euler12.erl 
lorenzo@enzo:~/erlang$time erl -s euler12 solve
Erlang R13B03 (erts-5.7.4) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.4  (abort with ^G)
1> 842161320

real    0m48.259s
user    0m48.070s
sys 0m0.020s

哈斯克尔:

lorenzo@enzo:~/erlang$ghc euler12.hs -o euler12.hsx
[1 of 1] Compiling Main             ( euler12.hs, euler12.o )
Linking euler12.hsx ...
lorenzo@enzo:~/erlang$time ./euler12.hsx 
842161320

real    2m37.326s
user    2m37.240s
sys 0m0.080s

摘要:

> C:100%
> Python:692%(使用PyPy时为118%)
> Erlang:436%(135%归功于RichardC)
> Haskell:1421%

我认为C有一个很大的优势,因为它使用long进行计算而不是任意长度整数作为其他三个.此外,它不需要首先加载运行时(其他人?).

问题1:
Erlang,Python和Haskell是否会因为使用任意长度整数而失去速度,或者只要值小于MAXINT就不会失败?

问题2:
为什么Haskell这么慢?是否有编译器标志关闭刹车或是我的实施? (后者非常可能,因为Haskell是一本带有七个印章的书.)

问题3:
您能否提供一些提示如何优化这些实现而不改变我确定因素的方式?以任何方式进行优化:更好,更快,更“本地”的语言.

编辑:

问题4:
我的功能实现是否允许LCO(最后一次调用优化,a.k.a尾递归消除),从而避免在调用堆栈中添加不必要的帧?

我真的试图在四种语言中尽可能地实现相同的算法,尽管我必须承认我的Haskell和Erlang知识非常有限.

使用的源代码:

#include <stdio.h>
#include <math.h>

int factorCount (long n)
{
    double square = sqrt (n);
    int isquare = (int) square;
    int count = isquare == square ? -1 : 0;
    long candidate;
    for (candidate = 1; candidate <= isquare; candidate ++)
        if (0 == n % candidate) count += 2;
    return count;
}

int main ()
{
    long triangle = 1;
    int index = 1;
    while (factorCount (triangle) < 1001)
    {
        index ++;
        triangle += index;
    }
    printf ("%ld\n", triangle);
}
#! /usr/bin/env python3.2

import math

def factorCount (n):
    square = math.sqrt (n)
    isquare = int (square)
    count = -1 if isquare == square else 0
    for candidate in range (1, isquare + 1):
        if not n % candidate: count += 2
    return count

triangle = 1
index = 1
while factorCount (triangle) < 1001:
    index += 1
    triangle += index

print (triangle)
-module (euler12).
-compile (export_all).

factorCount (Number) -> factorCount (Number, math:sqrt (Number), 1, 0).

factorCount (_, Sqrt, Candidate, Count) when Candidate > Sqrt -> Count;

factorCount (_, Sqrt, Candidate, Count) when Candidate == Sqrt -> Count + 1;

factorCount (Number, Sqrt, Candidate, Count) ->
    case Number rem Candidate of
        0 -> factorCount (Number, Sqrt, Candidate + 1, Count + 2);
        _ -> factorCount (Number, Sqrt, Candidate + 1, Count)
    end.

nextTriangle (Index, Triangle) ->
    Count = factorCount (Triangle),
    if
        Count > 1000 -> Triangle;
        true -> nextTriangle (Index + 1, Triangle + Index + 1)  
    end.

solve () ->
    io:format ("~p~n", [nextTriangle (1, 1) ] ),
    halt (0).
factorCount number = factorCount' number isquare 1 0 - (fromEnum $square == fromIntegral isquare)
    where square = sqrt $fromIntegral number
          isquare = floor square

factorCount' number sqrt candidate count
    | fromIntegral candidate > sqrt = count
    | number `mod` candidate == 0 = factorCount' number sqrt (candidate + 1) (count + 2)
    | otherwise = factorCount' number sqrt (candidate + 1) count

nextTriangle index triangle
    | factorCount triangle > 1000 = triangle
    | otherwise = nextTriangle (index + 1) (triangle + index + 1)

main = print $nextTriangle 1 1

解决方法:

在x86_64 Core2 Duo(2.5GHz)机器上使用GHC 7.0.3,gcc 4.4.6,Linux 2.6.29,使用ghc -O2 -fllvm -fforce-recomp为Haskell编译,gcc -O3 -lm为C编译.

>您的C例程在8.4秒内运行(可能因为-O3而比您的运行速度快)
> Haskell解决方案在36秒内运行(由于-O2标志)
>您的factorCount’代码没有明确输入并默认为Integer(感谢Daniel在这里纠正我的误诊!).使用Int提供显式类型签名(无论如何都是标准练习),时间更改为11.1秒
>在factorCount’你不必要地从整体上调用.修复导致没有变化(编译器很聪明,很幸运).
>你使用mod,其中rem更快更充足.这会将时间更改为8.5秒.
> factorCount’不断应用两个永不改变的额外参数(number,sqrt).工人/包装器转换为我们提供:

 $time ./so
 842161320  

 real    0m7.954s  
 user    0m7.944s  
 sys     0m0.004s  

没错,7.95秒.始终比C解决方案快半秒.如果没有-fllvm标志,我仍然会得到8.182秒,所以NCG后端在这种情况下也表现不错.

结论:Haskell非常棒.

结果代码

factorCount number = factorCount' number isquare 1 0 - (fromEnum $square == fromIntegral isquare)
    where square = sqrt $fromIntegral number
          isquare = floor square

factorCount' :: Int -> Int -> Int -> Int -> Int
factorCount' number sqrt candidate0 count0 = go candidate0 count0
  where
  go candidate count
    | candidate > sqrt = count
    | number `rem` candidate == 0 = go (candidate + 1) (count + 2)
    | otherwise = go (candidate + 1) count

nextTriangle index triangle
    | factorCount triangle > 1000 = triangle
    | otherwise = nextTriangle (index + 1) (triangle + index + 1)

main = print $nextTriangle 1 1

编辑:所以现在我们已经探索过,让我们解决问题

Question 1: Do erlang, python and haskell lose speed due to using
arbitrary length integers or don’t they as long as the values are less
than MAXINT?

在Haskell中,使用Integer比Int慢,但是慢多少取决于执行的计算.幸运的是(对于64位机器)Int就足够了.为了便于携带,您应该重写我的代码以使用Int64或Word64(C不是唯一具有long的语言).

Question 2: Why is haskell so slow? Is there a compiler flag that
turns off the brakes or is it my implementation? (The latter is quite
probable as haskell is a book with seven seals to me.)

Question 3: Can you offer me some hints how to optimize these
implementations without changing the way I determine the factors?
Optimization in any way: nicer, faster, more “native” to the language.

这就是我上面回答的问题.答案是

> 0)通过-O2使用优化
> 1)尽可能使用快速(特别是:unbox-able)类型
> 2)rem not mod(经常被遗忘的优化)和
> 3)worker / wrapper转换(也许是最常见的优化).

Question 4: Do my functional implementations permit LCO and hence
avoid adding unnecessary frames onto the call stack?

是的,那不是问题.干得好,很高兴你考虑过这个.

标签:c-3,python,performance,haskell,erlang
来源: https://codeday.me/bug/20190916/1807495.html