Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
128ビット4倍精度と160ビット拡張 4倍精度演算プログラムの作成
平山 弘 神奈川工科大学
自動車システム開発工学科 [email protected]
工学院大学 新宿校舎 28階 第4会議室 2013年3月8日(金)
なぜ4倍精度か
¡ 4倍精度程度の精度では、多倍長計算はあまり速くない。
¡ 精度の小さい計算の方が計算精度が大きい計算より需要は多い。
¡ 少ない精度で済む計算を大きな精度で計算するのはムダが大きい。
4倍精度数
¡
4倍精度の加算
¡ 4倍精度数を構造体で表す。 Fortran 90 C++言語 Type quad class quad { Real (8) :: high double high ; Real (8) :: low double low ; End Type quad }
負の数は、highとlowの符号を変える。
4倍精度数の加算
¡ Baileyの方法によって非常に簡単に書くことができる。 Function qq_add(a, b) ! Fortran 90 Type (quad), Intent (In) :: a, b Type (quad) :: qq_add Real (8) :: sh, eh, v, ss ! sh = a%high + b%high v = sh - a%high eh = (a%high-(sh-v)) + (b%high-v) eh = eh + a%low + b%low ss = sh + eh v = ss - sh qq_add%low = (sh-(ss-v)) + (eh-v) qq_add%high = ss End Function qq_add
条件判断の文が含まないので高速に計算できる可能性がある。
4倍精度の乗算
¡ 乗算も短いプログラムで記述できる。 quad operator*( const quad &b ) const // C++言語 { quad c ; double u1, p1, p2, r1, r2, s1 ; c.high = high * b.high ; u1 = 134217729.0* high ; // 134217729 = pow(2,27)+1 p1 = u1 - (u1 - high) ; p2 = high - p1 ; u1 = 134217729.0 * b.high ; r1 = u1 - (u1 - b.high) ; r2 = b.high - r1; c.low = ((p1*r1-c.high) + p1*r2 + p2*r1) + p2*r2 ; c.low = c.low + (high * b.low +low * b.high) ; s1 = c.high +c.low ; c.low =c.low - (s1 - c.high) ; c.high =s1 ; return c ; }
4倍精度数の2乗関数
¡ 乗算のプログラムからやや高速な2乗関数が作成できる。
Function q_square(a) Implicit None Type (quad), Intent (In) :: a Type (quad) :: q_square Real (8) :: u1, p1, p2, s1 q_square%high = a%high*a%high u1 = 134217729.0_dp*a%high p1 = u1 - (u1-a%high) p2 = a%high - p1 s1 = p1*p2 q_square%low = ((p1*p1-q_square%high)+s1+s1) + p2*p2 s1 = a%high*a%low q_square%low = q_square%low + (s1+s1) s1 = q_square%high + q_square%low q_square%low = q_square%low - (s1-q_square%high) q_square%high = s1 End Function q_square
4倍精度数の逆数関数(除算)
¡
4倍精度数の逆数関数プログラム
¡ 非常に簡単に書ける。 Function q_invers(a) Implicit None Type (quad), Intent (In) :: a Type (quad) :: q_invers, x x = to_quad_d(1.0_dp/a%high) !倍精度で逆数の近似値を計算 q_invers = x + x - a*q_square(x)!Newton法 End Function q_invers
これを使えば除算ができる。
4倍精度数の平方根逆数関数
¡ 平方根の逆数も逆数と同様に簡単に求められる。この場合、解くべき方程式は
¡ 近似値は倍精度で計算し、それから
Newton法を使う。
¡ 計算は加減乗算でできる。
21 0ax
− =
31 0.5( )n n n nx x x ax+ = + −
4倍精度数の関数
¡ 絶対値等 abs(x)、aint(x) ¡ 指数対数関数 exp(x)、log(x)、
log10(x) ¡ 三角関数 sin(x)、cos(x)、tan(x) ¡ 逆三角関数 asin(x)、acos(x)、atan(x) ¡ 双曲線関数 sinh(x)、cosh(x)、tanh(x) ¡ 逆双曲線関数 asinh(x)、acosh(x)、
atanh(x)
4倍精度数プログラムへ変換
¡ Fortran 90 subroutine add(a,b,c) c =a+b end
4倍精度への変換 倍精度 subroutine add(a,b,c) subroutine add(a,b,c) use def_quad type(quad) a, b,c real(8) a,b,c c =a+b c=a+b end end
FORTRAN77からFortran90へ変換
¡ コメントのCや*を!に変更 ¡ 継続行を&を使う継続行に変更 a=p+q+r+s * +t+u
を a=p+q+r+s & +t+u
4倍精度数プログラムへ変換
¡ C++言語 void add(double a, double b,double &c){ c =a+b ; }
4倍精度への変換 倍精度 #include “def_quad.h” void add(quad a,quad b, quad &c){ c =a+b ; }
4倍精度数独自の関数
¡ 4倍精度数への変換 a=to_quad(‘3.141592659265358979323846264’) a=to_quad(123)
4倍精度数から文字列へ変換 write(6,*) to_string(a,’e15.7’) cout << to_string(a,”%15.7e”)
プログラムの大きさ
Fortran 3300行 C++ 10000行
4倍精度数独自の関数
¡ 4倍精度数への変換 a=to_quad(‘3.141592659265358979323846264’) a=to_quad(123)
4倍精度数から文字列へ変換 write(6,*) to_string(a,’e15.7’) cout << to_string(a,”%15.7e”)
プログラムの大きさ Fortran 3300行 C++ 10000行
(使用した多倍長プログラムの違い)
4倍精度プログラム作成に使ったコンパイラ
¡ NAG Fortran 32ビット、64ビットのFortranコンパイラ 4倍精度実数(double-double)が組み込まれている。 (講演ではIEEE型と述べたが間違い)
¡ G95 32ビットの無料コンパイラ 80ビット実数と4倍精度(四則と平方根)実数が利用できる。
¡ Visual C++ 64ビットC++コンパイラ ¡ Borland C++ 32ビットC++コンパイラ 80ビット実数が使える。
簡単な拡張4倍精度プログラム例
¡ 2次方程式の計算(拡張4倍精度、g95)
¡ 約38桁の精度で計算されている。
簡単な4倍精度プログラム例
¡ 二重指数型数値積分の計算(4倍精度、g95) 大浦氏によるプログラムを変更
I_1=int_0^1 1/sqrt(x) dx I_1= 1.99999999999999999999999999999999E+0000 err= 4.00000000000000055539028735537525E-0030 n= 155 I_2=int_0^2 sqrt(4-x*x) dx I_2= 3.14159265358979323846264338327947E+0000 err= 6.28318530717958734933031009536329E-0030 n= 131
¡ 平方根、双曲線関数、指数関数を含むプログラムも容易に4倍精度に変換できる。
Fortran用Blasの4倍精度プログラム Blas関数のabsm関数の変更例 Fortran 90 FORTRAN 77 function wabsm(n,dx,incx) DOUBLE PRECISION FUNCTION WABSM(N,DX,INCX) type(quad), dimension(:) :: dx DOUBLE PRECISION DX(1),DTEMP type(quad) :: dtemp, wabsm INTEGER I,INCX,M,MP1,N,NINCX integer i,incx,m,mp1,n,nincx WABSM = 0.0D0 wabsm = 0.0d0 DTEMP = 0.0D0 dtemp = 0.0d0 IF(N.LE.0)RETURN if(n.le.0)return IF(INCX.EQ.1)GO TO 20 if(incx.ne.1) then NINCX = N*INCX nincx = n*incx DO 10 I = 1,NINCX,INCX do i = 1,nincx,incx DTEMP = DTEMP + DABS(DX(I)) dtemp = dtemp + abs(dx(i)) 10 CONTINUE end do WABSM = DTEMP wabsm = dtemp RETURN return 20 M = MOD(N,6) end if IF( M .EQ. 0 ) GO TO 40 m = mod(n,6) DO 30 I = 1,M if( m .eq. 0 ) go to 40 DTEMP = DTEMP + DABS(DX(I)) do i = 1,m 30 CONTINUE dtemp = dtemp + abs(dx(i)) IF( N .LT. 6 ) GO TO 60 end do 40 MP1 = M + 1 if( n .lt. 6 ) go to 60 DO 50 I = MP1,N,6 40 mp1 = m + 1 DTEMP = DTEMP + DABS(DX(I)) + DABS(DX(I + 1)) + DABS(DX(I + 2)) do i = mp1,n,6 * + DABS(DX(I + 3)) + DABS(DX(I + 4)) + DABS(DX(I + 5)) dtemp = dtemp + abs(dx(i)) + abs(dx(i + 1)) + abs(dx(i + 2)) & 50 CONTINUE + abs(dx(i + 3)) + abs(dx(i + 4)) + abs(dx(i + 5)) 60 WABSM = DTEMP end do RETURN 60 wabsm = dtemp END end function wabsm
Blasの4倍精度数プログラム
¡ C++言語 template化したBlasを使用 complexのtemplateを使用すれば 4倍精度の複素数計算が可能
4倍精度数プログラム性能
¡ 次のような性質の良い行列の逆行列を計算し、元の行列と掛けて単位行列を引く
¡ 各行列要素の絶対値最大の数値を求める。 行列は次のように与える。 ,
101i ji i j
ai j
+ =⎧= ⎨
≠⎩
4倍精度数プログラム性能(2)
¡ いろいろな大きさの行列について倍精度
で計算した。その実行時間を示す。 Intel i7-2700K(3.5GHz)
倍精度計算 (R8) 単位:秒
Nag
Fortran g95
Borland C++
Visual C++
CPU 32bit 64bit 32bit 32bit 64bit 100×100 0.0031 0.0016 0.0031 0.0042 0.0017 200×200 0.0230 0.0150 0.0210 0.0300 0.0120 300×300 0.0780 0.0530 0.0690 0.0980 0.0420 400×400 0.1830 0.2670 0.1580 0.2470 0.1120 500×500 0.3790 0.4450 0.3260 0.4560 0.2150
4倍精度数プログラム性能(3)
¡ いろいろな大きさの行列について計算した
。その実行時間を示す。 Intel i7-2700K(3.5GHz) Fortran
4倍精度計算 (R16) 単位:秒
行列のサイズ
Double-Double型 IEEE4倍精
度 160bit型
コンパイラ Nag Fortran g95 g95 g95
CPU 32bit 64bit 32bit 32bit 64bit 100×100 0.109 0.062 0.093 0.296 0.125 200×200 0.843 0.422 0.764 2.371 1.030 300×300 2.824 1.420 2.606 7.987 3.432 400×400 6.676 3.354 6.130 18.939 8.143 500×500 13.121 6.568 12.012 36.987 16.099
4倍精度数プログラム性能(4)
¡ いろいろな大きさの行列について計算した。その実行時間を示す。Intel i7-2700K(3.5GHz)
C++言語 単位:秒
4倍精度計算 (Double-Double) 行列のサイズ Double-Double型 160bit型
コンパイラ Visual C++ Borland 6.0 Borland 6.0
CPU 64bit 32bit 64bit 100×100 0.020 0.067 0.108 200×200 0.163 0.523 0.843 300×300 0.546 1.747 2.808 400×400 1.356 4.196 6.693 500×500 2.602 8.097 13.010
結論
¡ 4倍精度を持たない64ビットのC++コンパイラを使用する場合、double-double型の4倍精度は非常に高性能で、有用である。
¡ C++言語では、インライン展開されるためか、Fortranより高性能であった。
¡ 64ビットC++でdouble-double型の4倍精度数は、double型より11~14倍、32ビットなら15~18倍時間がかかる。
¡ 64ビットFortranで12~30倍、32ビットで35~38倍であった。 ¡ 拡張倍精度を利用した160ビット4倍精度はdouble-double
の4倍精度の1.5倍程度の計算時間を要する。 ¡ Fortran 90やC++言語を使うとその変更は単精度を倍精度
に変換する程度の作業でできる。
主な参考文献
¡ 山田,佐々,今村,町田, 4倍精度基本線形代数ルーチン群QPBLASの紹介とアプリケーションへの応用,情報処理学会研究報告, Vol.2012-HPC-137,No.23,1-6(2012)
¡ 小武守恒,藤井昭宏,長谷川秀彦,西田晃:反復法ライブラリ向け4倍精度演算の実装とSSE2 を用いた高速化,情報処理学会論文誌コンピューティングシステム,Vol.1, No. 1, pp. 73-84 (2008)