关于ocaml性能的测试(一)

(特注:这是一篇很无知的日记,我留着它只是为了记录我当初做了什么,而不是为了告诉别人什么)

今天用写了个计算Fibonacci数列的程序,顺便和C/C++比较一下效率。
要求:计算Fibonacci数列第38项是多少

递归的ocaml的

let rec fib  = function
   0 ->; 0
| 1 ->; 1
| n ->; fib (n-2) + fib (n-1);;
let main () =
 Printf.printf "%d" (fib 38);
 print_newline();
 exit 0;;
main();;

这个是递归的C的,编译为fibc

#include <stdio.h>;
int fib(int n){
   return n==0?0:
   n==1?1:
   fib(n-1)+fib(n-2);
}

int main(){
 int n=38;
 printf("%d\n",fib(n));
 return 0;
}

非递归的C++的,编译为fibc2

#include <iostream>;
#include <algorithm>;
int main(){
 const int n(38);
 int a(1),b(1);
 for(int i=2;i!=38;i++){
   a+=b;
   std::swap(a,b);
 }
 std::cout<<b<<std::endl;
 return 0;
}

编译时都加了-g选项加入了调试符号,没有加-O优化

第一个测试环境

所用C/C++编译器为

gcc (GCC) 3.4.4 [FreeBSD] 20050518
所用ocaml编译器为ocamlc 3.09.0
操作系统为FreeBSD 6.0p6
单CPU,AlthonXP 2400+
这个是运行结果
$ time ./fib
39088169
10.905u 0.000s 0:10.91 99.9% 154+921k 0+0io 0pf+0w

$ time ./fibc
39088169
0.950u 0.000s 0:00.95 100.0% 5+176k 0+0io 0pf+0w

$ time ./fibc2
39088169
0.003u 0.000s 0:00.00 0.0% 0+0k 0+0io 0pf+0w

可见非递归的C++版的所需时间几乎可以忽略不计,和递归版的相差2个数量级,至少300倍以上。 递归的ocaml和c的效率,相差10倍左右。

第二个测试环境

所用C/C++编译器为: gcc (GCC) 3.4.2 [FreeBSD] 20040728

所用ocaml编译器为: ocamlc 3.09.0

操作系统为: FreeBSD 5.4p13

双CPU,SMP系统,Intel(R) Xeon(TM) CPU 3.06GHz,HTT disabled

$ time ./fib
39088169
6.356u 0.000s 0:06.35 100.0% 148+886k 0+0io 0pf+0w

$ time ./fibc
39088169
0.933u 0.000s 0:00.93 100.0% 5+170k 0+0io 0pf+0w

$ time ./fibc2
39088169
0.004u 0.000s 0:00.01 0.0% 0+0k 0+0io 2pf+0w

这次对比不是那么明显了。我用gmp重写了递归的C++算法,并在第一台计算机上作测试

#include <stdio.h>
#include <gmpxx.h>
#include <iostream>
typedef  mpz_class INT;

template <typename T>

T  fib(const T n){
  return n==static_cast<T>;(0)?static_cast<T>;(0):
    n==static_cast<T>;(1)?static_cast<T>;(1):
    fib<T>;(n-1)+fib<T>;(n-2);
}

int main(){
 const INT n=38;
 std::cout<<fib<INT>;(n)<<std::endl;
 return 0;
}

所用时间远远在3min以上。我等不及,stop了。

换用非递归的算法

#include <stdio.h>
#include <gmpxx.h>
#include <iostream>

typedef  mpz_class INT_TYPE;

int main(){
 const INT_TYPE n(38000);
 INT_TYPE a(1),b(1);
 for(INT_TYPE i=2;i!=n;++i){
   a+=b;
   std::swap(a,b);
 }
 std::cout<<b<<std::endl;
 return 0;
}

计算第38000项,用了0.077s.

0.077u 0.000s 0:00.10 70.0% 5+219k 0+0io 1pf+0w

结论就不写了,因为这数据不是很准确。

写点感受

  1. 一般不要在C/C++中用递归。别扭,而且效率低
  2. gmp的效率的确很高。不过就是占用空间大了些。所以在递归的时候很吃亏
  3. ocaml是传说中最高效的functional language,但是与C相比而下,还是过于慢
  4. ocaml不适合作数值计算
  5. ocaml应该要比java慢,但是可能要比python快。

此博客中的热门博文

少写代码,多读别人写的代码

在windows下使用llvm+clang

tensorflow distributed runtime初窥