ページ

ラベル コンパイラー の投稿を表示しています。 すべての投稿を表示
ラベル コンパイラー の投稿を表示しています。 すべての投稿を表示

2016年5月6日金曜日

fortran 4倍精度で,計算速度はどの程度遅くなるか?

大学の環境で利用可能なコンパイラー
gfortran, ifort (intel), xl fortran (IBM), PGI fortran (NVIDIA)で
倍精度から4倍精度にした際にどの程度計算速度が遅くなるか比較する.
なお pgi fortranでは4倍精度のプログラムがコンパイルできなかったので,
実際には残りの3つの比較.

計算内容は割り算と掛け算をひたすら繰り返しただけ.

最適化(オプション)なしの比較.
----------------------- 結果1 (intel cpu)--------------------------------------

gfortran quadruple/double ratio
real: 9.6 倍遅延
complex : 19倍遅延

ifort quadruple/double ratio
real: 16倍 遅延
complex: 28倍遅延

efficiency (gfortran calc. time/ ifort calc. time)
gfortran -> ifort
real: 5.988sec/4.963sec -> 1.2倍 高速化
complex 22sec/16sec  ->1.3倍 高速化
(ifortの方がちょっとだけ早い)

--------------------------結果2 (ibm ワークステーション)------------------------

xlf90 quadruple/double ratio
real: 2.27倍遅延
complex: 5.83倍遅延

efficency  (gfortran -> xlf90)
gfortran 4.7.3で4倍精度コンパイルできなかったので比較できず.
(4.6から対応だと思っていたが・・・)

pgf90 4倍精度コンパイルできず...

-----------------------------------------------------------------------------
上記比較はオプションなしの場合.

ifortは倍精度は2-3倍オプションなしで早くなるが,
4倍精度では思ったより実力を発揮しなかった.
恐らく4倍精度はソフトウェア上での実装なので,最適化があまり意味がないのかと思う.
ただし,ifortの場合do文を自動並列化ができるので強制的に並列化してやれば,最大でcpu(thread)数倍くらい早くならないこともない.


ibmのコンパイラーはibmのマシーンに特化してる気もする.
他にもNAGや富士通(販売終了),absoftがあるらしいが,使ったこと無い.

価格2016年5月時点
IBM: $3380 
NAG: (63,000円) single user license 
Intel: 10-30万くらい (Parallel Studio XE Composer Edition)
PGI:5-10万くらい
absoft:6万-12万 
備考:intel compiler の非商用版(linuxのみ)は無償だったが,有償版だけになった模様.
学生に限りは無償使用のライセンスが在る模様.

2013年10月15日火曜日

gccの4倍精度ライブラリー

gcc 4.6 から4倍精度計算ができる様になりました.昔は4倍精度で計算できるマシンがあったみたいだけどね.

今回は、c, (c++はやってない), fortranの言語で実装するとしてどの言語が最も実装しやすいか比較する.
gcc のversionは4.8 を用いる.結論としてはfortranが一番楽だと思う.
cおよびc++は
http://homepage3.nifty.com/maikaze/float128.html
で解説されているようにc(, c++)では幾分実装が不自然な所もあるので,一応比較してみる.
計算する内容は1/3, 4*arctan(1)=pi,sqrt(2)である.

まずfortranから
program fort_quadmath
 implicit none
 real (kind(0D0)) dx, dy, dpi,dsqrt2
 real (kind(0Q0)) qx, qy, qpi,qsqrt2
 dx = 1.0D0;
 dy = 3.0D0;
 dsqrt2 = sqrt(2.0D0)
 dpi = 4.0D0*atan(1.0D0)
 qx = 1.0Q0;
 qy = 3.0Q0;
 qsqrt2 = sqrt(2.0Q0)
 qpi = 4.0Q0*atan(1.0Q0)
 print *, "---- double precision ----"
 print *, "1/3     =", dx/dy
 print *, "pi      =", dpi
 print *, "sqrt(2) =", dsqrt2
 print *, "----  quad  precision ----" 
 print *, "1/3     =", qx/qy
 print *, "pi      =", qpi
 print *, "sqrt(2) =", qsqrt2
end program fort_quadmath 
コンパイルは
 gfortran -o fort_quadmath fort_quadmath.f03 
であり,実行結果は
$ ./fort_quadmath 
 ---- double precision ----
 1/3     =  0.33333333333333331     
 pi      =   3.1415926535897931     
 sqrt(2) =   1.4142135623730951     
 ----  quad  precision ----
 1/3     =  0.333333333333333333333333333333333317      
 pi      =   3.14159265358979323846264338327950280      
 sqrt(2) =   1.41421356237309504880168872420969798   
 pi           3.1415926535897932384626433832795028841971693993751
 sqrt(2)      1.4142135623730950488016887242096980785696718753769
厳密解と比較して32桁くらいまでは遜色無く一致している.
実装に関して変数の型の宣言と、リテラル(0Q0)さえ気をつけていれば,関数の型を意識する必要がない(というか関数が代表名で与えられているので,変数の型によって関数が勝手に陰的に変わるんだと理解している.)

一方c言語に関して
#include <stdio.h>
#include <quadmath.h>
#include <math.h>

int main(void)
{
 char c1[80],c2[80],c3[80],c4[80],c5[80];
 double dx,dy,dpi;
 long double lx,ly,lpi;
 __float128 x,y, pi1,pi2,sqrt1,sqrt2;
 dx = 1.0;
 dy = 3.0;
 dpi = 4.0*atan(1.0);
 lx = 1.0L;
 ly = 3.0L;
 lpi = 4.0L*atan(1.0L);
 x = 1.0Q;
 y = 3.0Q;
 pi1 = 4.0Q*atan(1.0Q);
 pi2 = 4.0Q*atanq(1.0Q); 
 sqrt1 = sqrt(2.0Q);
 sqrt2 = sqrtq(2.0Q);  
 
 printf("---- double precision ----\n");
 printf("1/3 = %.30lf\n", dx/dy);
 printf("pi  = %lf\n", dpi); 
 printf("---- long double prescision ----\n");
 printf("1/3 = %.30Lf\n", lx/ly);
 printf("pi  = %.30Lf\n", lpi);
 printf("---- quad precision ----\n");
 quadmath_snprintf(c1,80,"%.40Qf", x/y);
 quadmath_snprintf(c2,80,"%.40Qf", pi1); 
 quadmath_snprintf(c3,80,"%.40Qf", pi2);  
 quadmath_snprintf(c4,80,"%.40Qf", sqrt1);  
 quadmath_snprintf(c5,80,"%.40Qf", sqrt2);    
 printf("1/3 = %s\n", c1);
 printf("pi1  = %s\n", c2);
 printf("pi2  = %s\n",c3);
 printf("sqrt1  = %s\n",c4);
 printf("sqrt2  = %s\n",c5);  
 return 0;
}
のコンパイルは
gcc -o c_quadmath c_quadmath.c -lquadmath
で行う.実行結果は
$ ./c_quadmath 
---- double precision ----
1/3 = 0.333333333333333314829616256247
pi  = 3.141593
---- long double prescision ----
1/3 = 0.333333333333333333342368351437
pi  = 3.141592653589793115997963468544
---- quad precision ----
1/3 = 0.3333333333333333333333333333333333172839
pi1  = 3.1415926535897931159979634685441851615906
pi2  = 3.1415926535897932384626433832795027974791
sqrt1  = 1.4142135623730951454746218587388284504414
sqrt2  = 1.4142135623730950488016887242096981769402
 
pi     3.1415926535897932384626433832795028841971693993751
sqrt(2)  1.4142135623730950488016887242096980785696718753769
の厳密解と比較して pi1とsqrt1がdouble程度の精度しかない. これは代入する変数の型と関数の返り値の型が一致していないため,関数の方の型で丸められてしまったせいだと考えられる.(c++でも?)
既存のプログラムの精度を倍精度から4倍精度に書き直すにはc言語では関数も書き換えなければならない. (gccがversion upしたらなんとかなるんか?) 精度の仕様変更に関しては圧倒的にfortranの方がいじりやすいと個人的に思う.
 (fortran はあんまり使ってないけどね・・・)