プログラミング言語 I 第 6 回 πの計算 1
埼玉大学工学部 電気電子システム工学科 伊藤 和人
Copyright © 2009 Kazuhito Ito
課題
π(円周率)を小数以下10,000桁まで計算 しなさい。
マーチンの公式を利用
⎟⎠
⎜ ⎞
⎝ + ⎛
⎟⎠
⎜ ⎞
⎝
− ⎛
⎟⎠
⎜ ⎞
⎝ + ⎛
⎟⎠
⎜ ⎞
⎝
= ⎛
110443 arctan 1
239 48 arctan 1
57 20 arctan 1
49 128 arctan 1
π 48
⎟⎠
⎜ ⎞
⎝
− ⎛
⎟⎠
⎜ ⎞
⎝
= ⎛
239 arctan 1
5 4 arctan 1
π 16
他にも、以下のような公式あり
⎟⎠
⎜ ⎞
⎝ + ⎛
⎟⎠
⎜ ⎞
⎝
− ⎛
⎟⎠
⎜ ⎞
⎝ + ⎛
⎟⎠
⎜ ⎞
⎝
= ⎛
12943 arctan 1
682 96 arctan 1
239 48 arctan 1
57 28 arctan 1
π 176
Copyright © 2009 Kazuhito Ito
πの計算
arctan
の計算 ⇒ テイラー展開を利用
+L
− +
−
− =
= ∞ − −
=
∑
(21) 1+ 3 5 7arctan
7 5
1 3 2 1
1 x x x
x i x
x i
i
i
= S
⋅ +
⋅ −
⋅ +
−
⎟ =
⎠
⎜ ⎞
⎝
⎛ 3 5 7 L
5 7
16 5
5 16 5
3 16 5
16 5
arctan 1 16
⎟ の場合
⎠
⎜ ⎞
⎝
⎛ 5 arctan 1 16
Copyright © 2009 Kazuhito Ito
テイラー展開による arctan 計算
5 16
1 =
T S = T1
25
3 1
T = T
3 T3
S S = −
25
5 3
T = T
5 T5
S S = +
25
7 5
T = T
7 T7
S
S = − Tn
が十分小さく なるまで繰り返す 除算、加算、減算 を実行
= S
⋅ +
⋅ −
⋅ +
−
⎟ =
⎠
⎜ ⎞
⎝
⎛ 3 5 7 L
5 7
16 5
5 16 5
3 16 5
16 5
arctan 1 16
Copyright © 2009 Kazuhito Ito
高精度演算の考え方
小数以下
10,000桁
= 10-10000の精度
細かな数値を表すための
C言語データ型
±1.175×10-38~±1.175×10+38 (32ビット、有効桁数7)
float double long double
±2.225×10-308~±2.225×10+308 (64ビット、有効桁数15)
±1.084×10-4932~±1.084×10+4932 (80ビット、有効桁数19)
long doubleを使用しても精度が不足 しかも、19桁分しか値を記憶できない
別の方法が 必要
Copyright © 2009 Kazuhito Ito
桁数の長い数 = 多倍長数
多数のデータ
(各桁の値
)をまとめて処理
整数型配列の各要素が桁の値を記憶
要素数を増やせば長い桁に対応可能 配列を利用
3.141592…
3 1 4 1 5 9 2 ・・・・ ..
int pi[] pi[0]
pi[1]pi[2]
pi[3]pi[4]
pi[5]
.
pi[6] pi[10000]
多倍長数という
Copyright © 2009 Kazuhito Ito
長い桁数の演算
C
言語では
int型データが基本演算単位
1
桁の演算と
2桁の演算はどちらも
int型
⇒ 計算時間は同じ
(同じ
1回の演算処理
) 1
回の
int型演算でなるべく多くの桁を計算さ せたい
1
つの要素が
M桁を表す場合、
乗算の過程で桁数が最大で
2M桁になる
int
型で
2M桁の整数が扱えるような桁数
Mを
選択
Copyright © 2009 Kazuhito Ito
長い桁数の演算
int
型ではなく
long型を指定 その理由は
…
現在の
32ビットプロセッサでは
int型と
long型 と同じ
⇒
long型演算を最短時間
(1クロック
)で実行
もし
16ビットプロセッサを使用したとしても、
long
型
=32ビットとして正しく実行できる
Copyright © 2009 Kazuhito Ito
要素の桁数の決定
long
型で扱える値の範囲
long
型の最大桁数と
Mの関係
M
として
4を選択
⇒
1つの要素が
0から
9999(4桁
)を表す 符号付
: -2,147,483,648~
2,147,483,647符号なし
: 0~
4,294,967,295(=232-1)(231-1)
の十進数桁数
= 9≧
2M(-231
~
231-1)Copyright © 2009 Kazuhito Ito
多倍長数と配列
小数点以下
10000桁を表すには
10000/4=2500
要素の配列が必要
桁と配列要素の対応 少なくとも
2通りあり
3. 1415 9265 3589 7932 3846 … 1989
3
2 4 249
1 0
配列添え字
246
247 245 0
248 249
配列添え字
π=
方法1 方法2
方法2を採用
除算(後述)の過程で、整数部分に拡張する場合あり 方法1では拡張不可能
以下は250要素の場合
Copyright © 2009 Kazuhito Ito
多倍長加算
下位桁から順に処理する
void LVadd( long a[], long b[] ){
long i, c=0;
for( i=0 ; i<N ; i++ ){
a[i] += (b[i]+c);
if( a[i] >= D ){
a[i] -= D;
c = 1;
}else{
c = 0;
} } }
#define N 2500
#define D 10000 として、
加算結果がD以上 ならば桁上げ
a ← a+b
Copyright © 2009 Kazuhito Ito
多倍長減算
下位桁から順に処理する
void LVsub( long a[], long b[] ){
long i, c=0;
for(i=0 ; i<N ; i++ ){
a[i] -= (b[i]+c);
if( a[i] < 0 ){
a[i] += D;
c = 1;
}else{
c = 0;
} } }
減算結果が負ならば 桁借り
a ← a-b
#define N 2500
Copyright © 2009 Kazuhito Ito
多倍長精度除算
被除数(割られる数): a = asDs + as−1Ds−1 +L+ a0 除数(割る数): b = btDt + bt−1Dt−1 +L+ b0
a<bの場合は除算は不要(q=0)なので a≧bとする すなわち
商: q = quDu + qu−1Du−1 +L+ q0 余り: r = rtDt + rt−1Dt−1 +L+ r0
r qb
a = +
(
0 ≤ r < b)
0 ,
0 ≠
≠ t
s b
a
Copyright © 2009 Kazuhito Ito
多倍長精度除算
0 1
1D b
b D
b
kb = t′ t + t′− t− +L+ ′
bをk倍した数 を考える
D D b
t′ <
2 ≤
ただし k は を満たす整数
計算を効率化するための工夫
a も k 倍すれば
( ) ( ) ( )
ka = q kb + kr であるから、z商は不変
z余りは除算後に 1/k 倍すればよい 以降では、予め被除数、除数とも k 倍し、
D D b
t <
2 ≤ が成り立つと仮定
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (3)
商の最上位桁位置
uおよび桁値
quを求める
の場合
のとき
t
s b
a ≥
t
bDs
a ≥ −
D a
D D b
s
t < <
≤ ,
2 であるから、 < 2 ⇒ < 2
t s t
s b
b a a
さらに ≥ 1
t s
b
a であり、商の最上位桁は1に定まる よって u = s − t, qu = 1
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (4)
の場合(続き)
のとき
t
s b
a ≥
t
bDs
a < −
1
1 −
− < t
s b
a とすれば a > bDs−t − Ds
よって u = s − t −1, qu = D − 2
または
D −1j t j
s t
s t
s b a b a b
a = , −1 = −1,K, − < −
(
j ≥1)
t t
t D D
D b
b ≥ ≥ 2 より 2b ≥ Dt+1 ⇒ 2bDs−t−1 ≥ Ds すなわちa > bDs−t − Ds ≥ bDs−t − 2bDs−t−1 = bDs−t−1
(
D − 2)
(
j =1)
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (5-1)
の場合
まず、簡単化のため の場合を考える
t
s b
a <
r Qb
a D
as + s−1 = t + とすれば ⎥
⎦
⎢ ⎥
⎣
⎢ +
≤ −
t s s
b a D
Q a 1
b Q a
b R a D
Q a
t s s
0 0
1
0 ⎥, = −
⎦
⎢ ⎥
⎣
⎢ +
= − とおく
+1
= t s
Q0は商の候補であるが、除数を小さく見積もって いる ため、 Q0が実際の商qより大きい、
すなわちR0が負になっている場合も存在する
(
bt Dt ≤ b)
商の候補を1増やしながら、余りが非負に なる真の商を見つける
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (5-2)
as < bt
の場合
(続き
)0
0, r R
Q
q ← ← とし、
を繰り返す b
r r qb
a = + , <
b Q a
b R a D
Q a
t s s
0 0
1
0 ⎥, = −
⎦
⎢ ⎥
⎣
⎢ +
= − とおく
≥ 0
r となるまで b
r r
q
q ← −1, ← +
だから
−1
>
⇒ +
< b
q a b
qb a
このとき
+1
= t
s の場合
繰り返し回数
⎟⎠
⎜ ⎞
⎝⎛ −
−
⎟ ≤
⎠
⎜ ⎞
⎝⎛ − + −
<
− −1 1 −1 1
0 b
a D
b a b
a b
a D
q a
Q s
t t
s s
※1
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (5-3)
as < bt
の場合
(続き
) s = t +1 の場合すなわち※1の操作は、高々2回繰り返せば 正しい商が得られる
1
1 1
1
0 1 ⎟⎟ +
⎠
⎜⎜ ⎞
⎝
= ⎛ −
⎟⎠
⎜ ⎞
⎝⎛ −
−
<
− − s− −
t
s t s
t b D
D b b
b a b
a D
b q a
Q (A)
+1
= t
s およびb − btDt = bt−1Dt−1 +L+ b0 < Dt より 3
1 1
1 1
1 ⎟⎟ + = + ≤
⎠
⎜⎜ ⎞
⎝
< ⎛
⎟⎟ +
⎠
⎜⎜ ⎞
⎝
⎛ −
−
−
t t
t t s
t
s t
b D D
b D D D
b
D b b
b
a (B)
式(A),(B)より、繰り返し回数 Q0 − q < 3
よって u = s − t −1 = 0, q0 = Q0 または Q0 −1または Q0 − 2
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (5-4)
as < bt
の場合
(一般の場合
)0 1
0D , r R
Q
q′ ← s−t− ′ ← とし、
を繰り返す r
b QD
r b
q
a = ′ + ′ = s−t−1 + ′ b D
Q a
b R a D
Q a s t
t s
s 1
0 1 0
0 − ⎥, = − − −
⎦
⎢ ⎥
⎣
⎢ +
= とおく
≥ 0
r′ となるまで b
D r
r D
q
q′ ← ′ − s−t−1, ′ ← ′ + s−t−1
だから
1 1
1
1 + ⇒ > −
< − − − − − −
b D
Q a b
D b
QD
a s t s t s t
このとき
繰り返し回数
⎟⎠
⎜ ⎞
⎝
⎛ −
+ −
<
− −1 − −1 1
0 D b
a b
a D
Q a
Q s t
t s s
※1
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (5-5)
as < bt
の場合
(一般の場合
) (続き
)1
1 1 1
1
1 ⎟ ≤ − +
⎠
⎜ ⎞
⎝
⎛ −
+ −
−
−
−
−
−
−
b D
a D
b a b
D a b
a D
a
t s s
t t
s t
s s
1
1 1
1
1 ⎟⎟ +
⎠
⎜⎜ ⎞
⎝
= ⎛ − +
−
= − − − − − − t
t
t t t
s t
s t
s t
t b D
D b b
b D
a b
D a D
D b
a
3 1
1 = + ≤
⎟⎟ +
⎠
⎜⎜ ⎞
⎝
< ⎛
t t
t t
b D D
b D D
よって、繰り返し回数 Q0 − Q < 3
2 1
,
1 = 0 0 − 0 −
−
−
= s t q Q Q Q
u u または または
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (6)
商の最上位桁位置
uおよび桁値
quを求める
の場合
のとき
のとき
の場合
t
s b
a ≥
t
bDs
a ≥ −
1
, =
−
= s t qu u
t
bDs
a < −
1 2
,
1 = − −
−
−
= s t q D D
u u
または
t
s b
a <
2 1
,
1 = 0 0 − 0 −
−
−
= s t q Q Q Q
u u または または
⎥⎦
⎢ ⎥
⎣
⎢ +
= −
t s s
b a D
Q0 a 1
ただし
Copyright © 2009 Kazuhito Ito
多倍長精度除算 (7)
商の最上位桁位置
uおよび桁値
quが得ら れたら
b D q a
r = − u u
a ← r として再度除算を実行
中間余り を計算
a < b になったとき、除算完了
Copyright © 2009 Kazuhito Ito
多倍長除算の例
D=10
として
41567÷
32を行う
0. D b D になるように被除数a、除数bをk倍する
t <
2 ≤
a=83134=8×104+3×103+1×102+3×10+4 k=2 として
b= 64= 6×10+4 1. 83134÷64 ⇒
t
s b
a ≥ , a ≥ bDs−t より ,
= 83134 – 64000=19134
= 3
−
= s t
u qu = q3 = 1
3 3 ×10
×
−
← a b q
a
6 ,
1 ,
8 ,
4 = = =
= as t bt
s
Copyright © 2009 Kazuhito Ito
多倍長除算の例 ( 続き 1)
2. 19134÷64 ⇒ より,
= 19134 – 12800=6334
t
s b
a < 3
6
1 19
0 =
⎥⎦⎥
⎢⎣⎢
⎥ =
⎦
⎢ ⎥
⎣
⎢ +
= −
t s s
b a D
Q a
64×3×102 = 19200 > 19134
64×9×10 = 5760 ≦ 6334
・・・NG
・・・OK 3. 6334÷64 ⇒
t
s b
a ≥ , a < bDs−t より
= 6334 – 5760=574
64×2×102 = 12800 ≦ 19134 ・・・OK 6
, 1 ,
1 ,
4 = = =
= as t bt
s
2 1 =
−
−
= s t
u ,
6 ,
1 ,
6 ,
3 = = =
= as t bt
s
2 2 ×10
×
−
← a b q
a
1 1 =
−
−
= s t
u , qu = q1 = 9 :
1 = 9 q
:
2 = 3 q
:
2 = 2 q
1 1 ×10
×
−
← a b q
a
Copyright © 2009 Kazuhito Ito
多倍長除算の例 ( 続き 2)
4. 574÷64 ⇒ より
= 574 – 512=62
t
s b
a < 9
6
1 57
0 =
⎥⎦⎥
⎢⎣⎢
⎥ =
⎦
⎢ ⎥
⎣
⎢ +
= −
t s s
b a D
Q a
64×9 = 576 > 574 ・・・NG 64×8 = 512 ≦ 574 ・・・OK
q3= 1, q2= 2, q1= 9, q0= 8 より
41567÷32 = 1298 あまり 62÷2=31 6
, 1 ,
5 ,
2 = = =
= as t bt
s
0 1 =
−
−
= s t
u ,
0 0 ×10
×
−
← a b q a
:
0 = 9 q
:
0 = 8 q
Copyright © 2009 Kazuhito Ito
多倍長除算の準備 (1)
良く使う関数を準備
void LVcopy( long a[], long b[] ) { int k;
for( k=N2-1 ; k>=0 ; k-- ) b[k] = a[k];
}long GetMSD( long a[] ) { int k;
for( k=N2-1 ; k>=0 ; k-- ){
if( a[k] ) break;
}return k;
}
多倍長数aの最上位 桁位置を求める
多倍長数aを多倍長数bへコピー
上位桁から順に調べ 非ゼロならば最上位
多倍長数がゼロならば戻り値は-1
Copyright © 2009 Kazuhito Ito
整数部を考慮
π
は整数部
(=3)あり
演算の過程で、整数部分に桁上げする場 合あり
整数部も統一的に扱うため、整数部まで桁 を拡張する
3. 1415 9265 3589 7932 3846 … 1989
246
247 245 0
248 249
拡張した部分
π =
N=250要素の場合
250 251
余裕をもって、配列2要素分(8桁)拡張
#define N2 (N+2)
Copyright © 2009 Kazuhito Ito
多倍長除算の準備 (2)
多倍長数に単精度数を乗じる
void LVmulS( long a[], long nb, long m[] ) { int k;
long w, nCarry = 0;
long nMSDa = GetMSD(a);
for( k=0 ; k<=nMSDa ; k++ ){
w = a[k]*nb + nCarry;
m[k] = w % D;
nCarry = w/D;
}m[k] = nCarry;
for( k++ ; k<N2 ; k++ ) m[k] = 0;
}
aの最上位桁 位置を求める
m ← a×nb
w≧Dならば桁上げ 下位からの 桁上げを加算
Copyright © 2009 Kazuhito Ito
多倍長除算の準備 (3)
除数の最上位桁を
D/2以上、
D未満にする
long Normalize( long b[], long c[] ) { long ns, v;
long nMSD = GetMSD(b);
v = b[nMSD];
if( v == 0 ) exit(1);
ns = D/(v+1);
if( ns > 1 ) LVmulS( b, ns, c );
else LVcopy( b, c );
return ns;
}
bの最上位桁 位置を求める bを正規化しcに代入
最上位桁が0なら終了
nsはb[nMSD]をD/2以上にするために 必要な最小係数
Copyright © 2009 Kazuhito Ito
多倍長除算 (1)
long LVdiv( long a0[], long b0[], long q[] ) { long s, t, k, u, nk;
long a[N2], b[N2];
nk = Normalize( b0, b );
LVmulS( a0, nk, a );
t = GetMSD( b );
for( k=0 ; k<N2 ; k++ ) q[k] = 0;
while(1){
if( Compare( a, b ) < 0 ) break;
// a < b ならば除算終了
} …
…
q ← a0/b0
bを正規化(nk倍) aもnk倍
商を0に 初期化
Copyright © 2009 Kazuhito Ito
多倍長除算 (2)
s = GetMSD( a );
if( a[s] >= b[t] ){
if( CompareOffset( a, b, s-t ) >= 0 ){
u = s-t; q[u] = 1;
}else{
u = s-t-1; q[u] = D-1;
}else{}
u = s-t-1; q[u] = (a[s]*D+a[s-1])/b[t];
}LVmulS( b, q[u], m );
while( CompareOffset( a, m, u ) < 0 ){
q[u]--;
LVmulS( b, q[u], m );
}
商の
最上位桁位置u および値q[u]の 候補を求める
a≧m=b×q[u]を満たす 最大のq[u]を求める
t を検査
bDs
a ≥ −
Copyright © 2009 Kazuhito Ito
多倍長除算 (3)
while( 1 ){
if( Compare( a, b ) < 0 ) break;
// a < b ならば除算終了
…
LVmulS( b, q[u], m );
while( CompareOffset( a, m, u ) < 0 ){
q[u]--;
LVmulS( b, q[u], m );
}LVsubOffset( a, m, u );
} a ← a – b×q[u]*Du
a≧m=b×q[u]を満たす 最大のq[u]を求める
u, q[u]の候補を求める(省略)
Copyright © 2009 Kazuhito Ito
多倍長除算の準備 (4)
int Compare( long a[], long b[] ) { int k;
long nMSDa = GetMSD(a);
long nMSDb = GetMSD(b);
if( nMSDa > nMSDb ) return 1;
if( nMSDa < nMSDb ) return -1;
for( k=nMSDa ; k>= 0 ; k-- ){
if( a[k] > b[k] ) return 1;
if( a[k] < b[k] ) return -1;
}return 0;
}
戻り値
a=b ⇒ 0 a>b ⇒ 1 a<b ⇒ -1
最上位桁が 同じ場合
多倍長数
aと
bを比較
すべて等しい ⇒ a=b
aの最上位桁が bの最上位桁より 上なら a>b
Copyright © 2009 Kazuhito Ito
多倍長除算の準備 (5)
int CompareOffset( long a[], long b[], long No ) { int k;
long nMSDa = GetMSD(a);
long nMSDb = GetMSD(b)+No;
if( nMSDa > nMSDb ) return 1;
if( nMSDa < nMSDb ) return -1;
for( k=nMSDa ; k>=No ; k-- ){
if( a[k] > b[k-No] ) return 1;
if( a[k] < b[k-No] ) return -1;
}for( ; k>=0 ; k-- ) if( a[k] ) return 1;
return 0;
}
多倍長数
aと
bを桁をずらして比較
a[No-1]から a[0]の中に 非ゼロのもの があれば
aの方が大きい
ここに来たときa[nMSDa],...,a[No]と b[nMSDa-No],...,b[0]が一致
Copyright © 2009 Kazuhito Ito
多倍長除算の準備 (6-1)
void LVsubOffset( long a[], long b[], long No ) { int k;
long v = 0;
long nMSDb = GetMSD(b);
for( k=0 ; k<=nMSDb ; k++ ){
if( a[k+No] >= b[k]+v ){
a[k+No] –= (b[k]+v); v = 0;
}else{
a[k+No] += D;
a[k+No] –= (b[k]+v); v = 1;
} }
a ← a – b×DNo
桁借りが ある場合
多倍長数
aから
bを桁をずらして引き算
最上位桁 までbを引く
次のスライドへ続く
Copyright © 2009 Kazuhito Ito
多倍長除算の準備 (6-2)
void LVsubOffset( long a[], long b[], long No ) { …
for( ; v ; k++ ){
if( a[k+No] ){
a[k+No]--; v = 0;
}else{
a[k+No] = D-1; v = 1;
} } }
上位桁への桁借りを 処理
多倍長数
aと
bを比較
前のスライドから続き
Copyright © 2009 Kazuhito Ito
被除数と除数の桁あわせ (1)
多倍長数が表す数
0 N-2
N-1
A’ =
N N+1
(D=10000)
∑
+=
= 1
0
D ] [ a ' N
k
k k
A
配列添え字
やはり整数 多倍長除算結果(商)
∑
+=
=
= 1
0
D ] [ ' q
' ' N
k
k k
B Q A
多倍長除算は、多倍長数aが整数値を表すと想定 多倍長数a
1 2345 6789 … 9012
要素の値 整数値
6789 2345
1
0 9012
小数点 位置