Fortran的准确性和速度vs. C



这个话题可能已经讨论过几百次了。我不是想说什么任何语言都有好坏之分。我只是想学习如何加速我的C代码。这里有两个计算圆周率的代码。

第一个是Fortran90:

program calcpi
implicit none
integer :: i
real*8 :: pi
pi=0.0
do i = 0,1000000000
   pi = pi + 1.0/(4.0*i+1.0)
   pi = pi - 1.0/(4.0*i+3.0)
end do
pi = pi * 4.0
write(*,*) pi
end program calcpi

第二个在C:

#include<stdio.h>
#define STEPCOUNTER 1000000001
int main(int argc, char * argv[])
{
long i;
double pi=0;
#pragma omp parallel for reduction(+: pi)
for ( i=0 ; i < STEPCOUNTER; i++){
   /*pi/4=1/11/3+1/51/7+...
   To avoid the need to continually change
   the sign (s=1; in each step s=s*-1 ),
   we add two elements at the same time.*/
   pi+=1.0/(i*4.0+1.0);   
   pi-=1.0/(i*4.0+3.0);   
//   pi = pi +  1.0/(i*4.0+1.0);
//   pi = pi -  1.0/(i*4.0+3.0);
}
 pi=pi*4.0;
 printf("Pi=%lfn",pi);
return 0;
}

我在CentOS 6机器上使用gcc版本4.4.4编译这两个代码。

[oz@centos ~]$ gfortran calcpi.f90 -o calcpi.fort.o
[oz@centos ~]$ gfortran calcpi.c -o calcpi.c.o   

CPU为Intel(R) Xeon(R) CPU 5160 @ 3.00GHz。

那么,下面是运行每段代码所花费的时间:

[oz@centos ~]$ time ./calcpi.c.o 
Pi=3.141593
real    0m33.270s
user    0m33.261s
sys     0m0.000s
[oz@centos ~]$ time ./calcpi.fort.o 
   3.1415926553497115     
real    0m27.220s
user    0m27.208s
sys     0m0.001s

Fortran大约快20%。我的问题是什么是最好的编译器标志来加速,但仍然保持稳定性和准确性?

(是的,我知道man gcc,我想知道用户的意见)。

谢谢你的意见。

结果,没有OpenMP pragma:

[oz@centos ~]$ time ./calcpi.c.o 
Pi=3.141593
real    0m32.892s
user    0m32.885s
sys     0m0.001s

不改变代码本身的其他结果:

$ gcc -O2 calcpi.c -o calcpi.c.o
$ time ./calcpi.c.o 
Pi=3.141593
real    0m21.085s
user    0m21.078s
sys     0m0.000s
$ gfortran -O2 calcpi.c -o calcpi.c.o
$ time ./calcpi.fort.o 
   3.1415926553497115     
real    0m26.892s
user    0m26.888s
sys     0m0.000s

修改Fortran程序,使其所有计算都采用双精度,从而与C版本相对应:

<>之前 program calcpi implicit none integer :: i integer, parameter :: p = selected_real_kind(15) real(p) :: pi pi=0.0_p do i = 0,1000000000 pi = pi + 1.0_p/(4.0_p*i+1.0_p) pi = pi - 1.0_p/(4.0_p*i+3.0_p) end do pi = pi * 4.0_p write(*,*) pi end program calcpi 之前

在Xeon X3450 (2.67 GHz)上使用GCC 4.4.3在x86_64-linux-gnu上使用-O2编译,我得到以下时间:

<>之前$ time ./calcpi_cπ= 3.141593真正的0 m13.903s用户0 m13.860ssys 0 m0.010s$ time ./calcpi_fort3.1415926530880767真正的0 m13.876s用户0 m13.840ssys 0 m0.000s之前

低,它们或多或少难以区分。对于这样一个简单的例子,这是人们所期望的。

最新更新