3

この主題はおそらく何百回も議論されてきました。私はどの言語もより悪いまたはより良いと主張しようとはしていません。Cコードを高速化する方法を学ぼうとしています。したがって、ここに円周率を計算するための2つのコードがあります。

1つ目は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

2番目は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=%lf\n",pi);
return 0;
}

CentOS6マシンで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プラグマなし:

[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
4

1 に答える 1

14

すべての計算を倍精度で行うことにより、C バージョンに対応するように Fortran プログラムを変更します。


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) 上の x86_64-linux-gnu で GCC 4.4.3 を使用して -O2 でコンパイルすると、次のタイミングが得られます。

$時間./calcpi_c
円周率=3.141593

実質 0 分 13.903 秒
ユーザー 0 分 13.860 秒
システム 0m0.010s
$ time ./calcpi_fort
   3.1415926530880767     

実質 0 分 13.876 秒
ユーザー 0 分 13.840 秒
システム 0m0.000s

IOW、それらは多かれ少なかれ区別がつきません。これは、このような単純な例に期待されることです。

于 2011-12-13T11:36:00.313 に答える