我最初写这个(蛮力和低效)与确保的意图计算素数的方法,有使用“IF-THEN-ELSE”与Haskell中后卫(并没有什么区别!)之间的速度没有区别。 但后来我决定写一个C程序来比较和我得到了以下(Haskell的速度慢一些刚刚超过25%):
(请注意我用的REM,而不是国防部的观点,并从编译器调用的O3选项下面的帖子: 在与C在斐波那契微基准提高Haskell的性能 )
哈斯克尔:Forum.hs
divisibleRec :: Int -> Int -> Bool
divisibleRec i j
| j == 1 = False
| i `rem` j == 0 = True
| otherwise = divisibleRec i (j-1)
divisible::Int -> Bool
divisible i = divisibleRec i (i-1)
r = [ x | x <- [2..200000], divisible x == False]
main :: IO()
main = print(length(r))
C:main.cpp中
#include <stdio.h>
bool divisibleRec(int i, int j){
if(j==1){ return false; }
else if(i%j==0){ return true; }
else{ return divisibleRec(i,j-1); }
}
bool divisible(int i){ return divisibleRec(i, i-1); }
int main(void){
int i, count =0;
for(i=2; i<200000; ++i){
if(divisible(i)==false){
count = count+1;
}
}
printf("number of primes = %d\n",count);
return 0;
}
我得到的结果如下:
编译时间
time (ghc -O3 -o runProg Forum.hs)
real 0m0.355s
user 0m0.252s
sys 0m0.040s
time (gcc -O3 -o runProg main.cpp)
real 0m0.070s
user 0m0.036s
sys 0m0.008s
和下面的运行时间:
在Ubuntu 32位运行时间
Haskell
17984
real 0m54.498s
user 0m51.363s
sys 0m0.140s
C++
number of primes = 17984
real 0m41.739s
user 0m39.642s
sys 0m0.080s
我是哈斯克尔的运行时间相当深刻的印象。 但是我的问题是这样的:我可以做任何事情,以加快Haskell的程序而不:
- 改变底层的算法(很显然,大规模的加速可以通过改变算法来获得,但我只是想了解什么,我可以在语言/编译器侧做,以提高性能)
- 调用LLVM编译器(因为我没有这个安装)
[编辑:内存使用]
阿伦评论后,我注意到,在C程序使用的内存恒定的量,其中作为Haskell的计划增长缓慢的内存大小。 起初我以为这有一些东西需要用递归,但GSPR下面解释为什么发生这种情况,并提供了解决方案。 将尼斯提供了一种替代的解决方案,其中(像GSPR的溶液)也确保了存储器保持静态。
[编辑:更大的运行概要]
最大号测试:200000:
(54.498s / 41.739s)= Haskell的慢30.5%
最大号测试40万:
3m31.372s / 2m45.076s = 211.37s / 165S = Haskell的慢28.1%
最大号测试80万:
14m3.266s / 11m6.024s = 843.27s / 666.02s = Haskell的慢26.6%
[编辑:代码艾伦]
这是我此前不具备递归和我20万测试编写的代码:
#include <stdio.h>
bool divisibleRec(int i, int j){
while(j>0){
if(j==1){ return false; }
else if(i%j==0){ return true; }
else{ j -= 1;}
}
}
bool divisible(int i){ return divisibleRec(i, i-1); }
int main(void){
int i, count =0;
for(i=2; i<8000000; ++i){
if(divisible(i)==false){
count = count+1;
}
}
printf("number of primes = %d\n",count);
return 0;
}
对于具有和不具有递归C代码的结果如下(为80万):
递归:11m6.024s
如果没有递归:11m5.328s
注意,可执行似乎占用60KB(如系统监视看到的),而不管最大数量的,因此我怀疑是编译器检测该递归。