■超幾何関数を用いた確率分布の計算(その3)
方程式f(x)=0が因数分解できる場合は,その根は簡単に求めることができますが,解析的に求まらない場合は数値計算法によらなければなりません.もちろん,問題の解としては可能な限り厳密なものが望まれますが,非線形方程式では,多くの場合,厳密な解析解を得るのは非常にやっかいであり,その点,数値的近似解ならアプローチしやすく手早く求めることができるため,たいていの非線形方程式の求根問題には逐次法(反復法)が用いられます.
非線形方程式の解を求める一般的な方法としては,ニュートン法がよく使われます.ニュートン方法は,ある初期値x0を定め,漸化式
xi+1=xi−f(xi)/f’(xi)
を反復させることによって,逐次,根に収束させていく方法ですが,その幾何学的な意味は
1)初期値x0における関数の勾配を求めて接線とx軸との交点を求める.
2)この点において同様の作業を行なうと,xは順次根に近づいてゆく.
と解釈されます.そして,xの変化があらかじめ与えた許容誤差以内になったとき,そのxをもって根と判定します.
確率分布の計算においても,十分な精度が得られるまで反復して解を求めますが,コラム「超幾何関数を用いた確率分布の計算」その1・その2では,精度と速度のせめぎ合いについて述べてきました.数値計算では精度と速度の2つが要請されますが,一般的にいって,精度を上げれば速度が下がり,速度を上げれば精度が下がります.すなわち,この2つの条件は競合的かつ背反的で,一方を減らすと他方が増えるというトレードオフの関係にあり,同時に向上させることは難しいとされます.これまで掲げてきた確率分布の計算プログラムではもっぱら精度を追求してきましたが,数値計算の精度・速度を論ずる以前の問題として,安定的に解が得られることが必要になります.
逐次法では,まずおおざっぱな近似解を何らかの方法で見積もり,次に近似解を逐次改良していき望みの精度が得られるまで続けます.ところが,初期値によっては真の根より遠のく場合があります.そして,このようなことが連鎖的に起こると計算は収束せずに発散してしまいます.解決策としては,初期値x0を決めるときに,f(x0)とf”(x0)とが同符号,すなわち,f(x0)・f”(x0)>0になるようなx0を選べば収束が安定化します.
このように,収束の安定化のためには2次までの微分を計算する必要がありますが,今回のコラムでは,ニュートン法のサブルーチンを改良し,収束を安定化を図ってみます.収束の安定化は,発散を防止し,最終収束までの所要時間を短縮しますから,結果的に収束を速くするためにも寄与してくれます.
===================================
【非線形方程式の解法】
(1)ニュートン法とベイリー法
1変量関数f(x)=0の近似解をx0とし,点x0でこの関数をテイラー展開して,べき級数で近似すると,
f(x)=f(x0)+f’(x0)(x−x0)+f”(x0)(x−x0)^2/2+高次項・・・
になります.ここで2次以上の項を無視すると1次近似式
f(x)≒f(x0)+f’(x0)(x−x0)=0
により,ニュートン法の漸化式
xi+1=xi−f(xi)/f’(xi)=xi−fi/fi’
が得られます.ここで,Δxi=xi+1−xiとおくと,ニュートン法は
Δx=−f(x)/f’(x)
と書くことができます.この式を反復させることによって根に収束させていく逐次法がニュートン法です.
また,3次以上の高次項を無視した2次近似式
f(x)≒f(x0)+f’(x0)(x−x0)+f”(x0)(x−x0)^2/2=0
より
(x−x0){f’(x0)+f”(x0)(x−x0)}=−f(x0)
ここで,括弧{・・・}の中の(x−x0)に,ニュートン法より−f(xi)/f’(xi)を代入すると,漸化式
xi+1=xi−1/{f’(xi)/f(xi)−f”(xi)/f’(xi)/2}
=xi−fi/(fi’−fifi”/2fi’)
が得られます.この式を利用した逐次法が,ベイリー法です.
ニュートン法は2次収束,ベイリー法は3次収束なので,ベイリー法はニュートン法より速く収束しますが,反復回数は少ないかわりに2次導関数を計算する必要があるため,計算量が増すので結局大差ないことになります.一般的にいって,ニュートン法のほうがかえって効率的であることが多いようです.
(2)2次までの微分を用いたニュートン法
ニュートン法:
Δx=−f/f’
にせよ,ベイリー法:
Δx=−f/(f’−ff”/2f’)
にせよ,f’(x)=0または0に近いときはそのままでは使えません.
その場合,テイラー展開において2次の項までを考慮してf(x)=0とおけば,Δx=x−x0に関する2次方程式
f+f’Δx+f”Δx^2/2=0
が得られることから,以下に掲げるプログラムでは,
Δx={−f’±√(f’f’−2ff”)}/f” (根の公式)
=2f/{−f’±√(f’f’−2ff”)} (分子の有理化)
としてΔxを求めています.この式は根号の中が負にならないときのみ適用可能で,複号はf’≧0のとき−を,f’<0のとき+を選択します.また,根号の中が負のときはΔx=−f/f’(ニュートン法)とします.
(改良前)
3080 '
3090 ' ** 逐次計算 **
3100 '
3110 IF PROB$="N" THEN UUN=D0:GOSUB *NORMAL.PROB.HGF
3120 IF PROB$="X" THEN UUX=D0:GOSUB *CHI2.PROB.HGF
3130 IF PROB$="T" THEN UUT=D0:GOSUB *T.PROB.HGF
3140 IF PROB$="F" THEN UUF=D0:GOSUB *F.PROB.HGF
3150 F=P0-Q0:G=P1
3160 DD=D0-F/G
3170 IF ABS(DD-D0)<EPSL THEN SW=1
3180 RETURN
(改良後)
1510 '
1520 ' ** 逐次計算 **
1530 '
1540 IF PROB$="N" THEN UUN=D0:GOSUB *NORMAL.PROB.HGF
1550 IF PROB$="X" THEN UUX=D0:GOSUB *CHI2.PROB.HGF
1560 IF PROB$="T" THEN UUT=D0:GOSUB *T.PROB.HGF
1570 IF PROB$="F" THEN UUF=D0:GOSUB *F.PROB.HGF
1580 F=P0-Q0:G=P1
1590 IF NEWTON=0 THEN DELTA=-F/G:GOTO 1650
1600 '
1610 H=P2:DI=G*G-F*H*2
1620 IF DI<0 THEN DELTA=-F/G:GOTO 1650
1630 IF G<0 THEN DELTA=F*2/(-G+SQR(DI)) ELSE DELTA=F*2/(-G-SQR(DI))
1640 '
1650 DD=D0+DELTA
1660 IF ABS(DD-D0)<EPSL THEN SW=1
1670 RETURN
改良後のプログラムでは,フラグ変数newtonを0にすると1次の微分を用いたニュートン法,フラグを立てる(0以外にする)と2次までの微分を用いたニュートン法で計算してくれます.
===================================
【プログラム】(2次までの微分を用いたニュートン法)
1000 '
1010 ' ** NORMAL DISTRIBUTION **
1020 '
1030 *NORMAL.PERCENT.HGF:
1040 PP=1-P0:GOSUB *NORMAL.PERCENT:UU=UUN
1050 PROB$="N":GOSUB *NEWTON.HGF
1060 UUN=X
1070 RETURN
1080 '
1090 ' ** CHI-SQUARE DISTRIBUTION **
1100 '
1110 *CHI2.PERCENT.HGF:
1120 PP=1-P0:GOSUB *CHI2.PERCENT:UU=UUX
1130 PROB$="X":GOSUB *NEWTON.HGF
1140 UUX=X
1150 RETURN
1160 '
1170 ' ** T-DISTRIBUTION **
1180 '
1190 *T.PERCENT.HGF:
1200 PP=1-P0:GOSUB *T.PERCENT:UU=UUT
1210 PROB$="T":GOSUB *NEWTON.HGF
1220 UUT=X
1230 RETURN
1240 '
1250 ' ** F-DISTRIBUTION **
1260 '
1270 *F.PERCENT.HGF:
1280 PP=1-P0:GOSUB *F.PERCENT:UU=UUF
1290 PROB$="F":GOSUB *NEWTON.HGF
1300 UUF=X
1310 RETURN
1320 '
1330 ' *** ニュートン法 ***
1340 '
1350 *NEWTON.HGF:
1360 EPSL=1E-09
1370 IMAX=50
1380 '
1390 Q0=P0
1400 D0=UU
1410 '
1420 SW=0
1430 ICNT=0
1440 WHILE SW=0
1450 ICNT=ICNT+1
1460 IF ICNT>IMAX THEN SW=1
1470 DD=D0:GOSUB 1510:D0=DD
1480 WEND
1490 X=DD
1500 RETURN
1510 '
1520 ' ** 逐次計算 **
1530 '
1540 IF PROB$="N" THEN UUN=D0:GOSUB *NORMAL.PROB.HGF
1550 IF PROB$="X" THEN UUX=D0:GOSUB *CHI2.PROB.HGF
1560 IF PROB$="T" THEN UUT=D0:GOSUB *T.PROB.HGF
1570 IF PROB$="F" THEN UUF=D0:GOSUB *F.PROB.HGF
1580 F=P0-Q0:G=P1
1590 IF NEWTON=0 THEN DELTA=-F/G:GOTO 1650
1600 '
1610 H=P2:DI=G*G-F*H*2
1620 IF DI<0 THEN DELTA=-F/G:GOTO 1650
1630 IF G<0 THEN DELTA=F*2/(-G+SQR(DI)) ELSE DELTA=F*2/(-G-SQR(DI))
1640 '
1650 DD=D0+DELTA
1660 IF ABS(DD-D0)<EPSL THEN SW=1
1670 RETURN
1680 '
1690 ' ** NORMAL DISTRIBUTION **
1700 '
1710 *NORMAL.PROB.HGF:
1720 PI#=3.141592653589732#
1730 A0=1:C0=1.5
1740 A=A0:C=C0
1750 Z=UUN*UUN/2:GOSUB *CONFLUENT.HGF:G1#=G#
1760 P0=.5#+G1#*UUN*EXP(-UUN*UUN/2)/SQR(PI#*2)
1770 '
1780 A=A0+1:C=C0+1
1790 Z=UUN*UUN/2:GOSUB *CONFLUENT.HGF:G2#=G#*A0/C0
1800 P10=G1#*(1-UUN*UUN)+G2#*UUN*UUN
1810 P1=P10*EXP(-UUN*UUN/2)/SQR(PI#*2)
1820 '
1830 IF NEWTON=0 THEN 1880
1840 A=A0+2:C=C0+2
1850 Z=UUN*UUN/2:GOSUB *CONFLUENT.HGF:G3#=G#*A0/C0*(A0+1)/(C0+1)
1860 P20=-P10*UUN+G2#*UUN*(1-UUN*UUN)-G1#*UUN*2+G3#*UUN*UUN*UUN+G2#*UUN*2
1870 P2=P20*EXP(-UUN*UUN/2)/SQR(PI#*2)
1880 RETURN
1890 '
1900 ' ** CHI-SQUARE DISTRIBUTION **
1910 '
1920 *CHI2.PROB.HGF:
1930 A0=1:C0=1+DF/2
1940 A=A0:C=C0
1950 Z=UUX/2:GOSUB *CONFLUENT.HGF:G1#=G#
1960 Z=1+DF/2:GOSUB *LOG.GAMMA:G2#=G#
1970 P0=G1#/EXP(G2#)*(UUX/2)^(DF/2)*EXP(-UUX/2)
1980 '
1990 A=A0+1:C=C0+1
2000 Z=UUX/2:GOSUB *CONFLUENT.HGF:G3#=G#*A0/C0
2010 P10=(DF/2*(UUX/2)^(DF/2-1)-(UUX/2)^(DF/2))*G1#/2+(UUX/2)^(DF/2)*G3#/2
2020 P1=P10/EXP(G2#)*EXP(-UUX/2)
2030 '
2040 IF NEWTON=0 THEN 2090
2050 A=A0+2:C=C0+2
2060 Z=UUX/2:GOSUB *CONFLUENT.HGF:G4#=G#*A0/C0*(A0+1)/(C0+1)
2070 P20=-P10/2+(DF/2*(DF/2-1)*(UUX/2)^(DF/2-2)-DF/2*(UUX/2)^(DF/2-1))*G1#/4+(DF/2*(UUX/2)^(DF/2-1)-(UUX/2)^(DF/2))*G3#/4+DF/2*(UUX/2)^(DF/2-1)*G3#/4+(UUX/2)^(DF/2)*G4#/4
2080 P2=P20/EXP(G2#)*EXP(-UUX/2)
2090 RETURN
2100 '
2110 ' ** T-DISTRIBUTION **
2120 '
2130 *T.PROB.HGF:
2140 DFX=DF/2:DFY=.5
2150 A0=DFX+DFY:B0=1:C0=DFX+1
2160 A=A0:B=B0:C=C0
2170 Z=DF/(DF+UUT*UUT):GOSUB *GAUSS.HGF:G1#=G#
2180 P0=G1#/DFX*Z^DFX*(1-Z)^DFY
2190 Z=DFX+DFY:GOSUB *LOG.GAMMA:G2#=G#
2200 Z=DFX :GOSUB *LOG.GAMMA:G3#=G#
2210 Z=DFY :GOSUB *LOG.GAMMA:G4#=G#
2220 P0=P0*EXP(G2#-G3#-G4#)
2230 P0=P0/2
2240 P0=1-P0
2250 '
2260 A=A0+1:B=B0+1:C=C0+1
2270 Z=DF/(DF+UUT*UUT):GOSUB *GAUSS.HGF:G5#=G#*A0*B0/C0
2280 ZZ=-DF*UUT*2/(DF+UUT*UUT)^2
2290 P10=(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G1#+Z^DFX*(1-Z)^DFY*G5#
2300 P1=-P10*ZZ/DFX*EXP(G2#-G3#-G4#)/2
2310 '
2320 IF NEWTON=0 THEN 2390
2330 A=A0+2:B=B0+2:C=C0+2
2340 Z=DF/(DF+UUT*UUT):GOSUB *GAUSS.HGF:G6#=G#*A0*B0/C0*(A0+1)*(B0+1)/(C0+1)
2350 ZZ=-DF*UUT*2/(DF+UUT*UUT)^2
2360 ZZZ=-DF*2*(DF-UUT*UUT*3)/(DF+UUT*UUT)^3
2370 P20=P10*ZZZ+((DFX*(DFX-1)*Z^(DFX-2)*(1-Z)^DFY-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)+Z^DFX*DFY*(DFY-1)*(1-Z)^(DFY-2))*G1#+(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G5#+Z^DFX*(1-Z)^DFY*G6#)*ZZ*ZZ
2380 P2=-P20/DFX*EXP(G2#-G3#-G4#)/2
2390 RETURN
2400 '
2410 ' ** F-DISTRIBUTION **
2420 '
2430 *F.PROB.HGF:
2440 A0=DFX+DFY:B0=1:C0=DFX+1
2450 A=A0:B=B0:C=C0
2460 Z=DF2/(DF2+DF1*UUF):GOSUB *GAUSS.HGF:G1#=G#
2470 P0=G1#/DFX*Z^DFX*(1-Z)^DFY
2480 Z=DFX+DFY:GOSUB *LOG.GAMMA:G2#=G#
2490 Z=DFX :GOSUB *LOG.GAMMA:G3#=G#
2500 Z=DFY :GOSUB *LOG.GAMMA:G4#=G#
2510 P0=P0*EXP(G2#-G3#-G4#)
2520 P0=1-P0
2530 '
2540 A=A0+1:B=B0+1:C=C0+1
2550 Z=DF2/(DF2+DF1*UUF):GOSUB *GAUSS.HGF:G5#=G#*A0*B0/C0
2560 ZZ=-DF2*DF1/(DF2+DF1*UUF)^2
2570 P10=(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G1#+Z^DFX*(1-Z)^DFY*G5#
2580 P1=-P10*ZZ/DFX*EXP(G2#-G3#-G4#)
2590 '
2600 IF NEWTON=0 THEN 2670
2610 A=A0+2:B=B0+2:C=C0+2
2620 Z=DF2/(DF2+DF1*UUF):GOSUB *GAUSS.HGF:G6#=G#*A0*B0/C0*(A0+1)*(B0+1)/(C0+1)
2630 ZZ=-DF2*DF1/(DF2+DF1*UUF)^2
2640 ZZZ=-DF2*DF1*DF1*2/(DF2+DF1*UUF)^3
2650 P20=P10*ZZZ+((DFX*(DFX-1)*Z^(DFX-2)*(1-Z)^DFY-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)+Z^DFX*DFY*(DFY-1)*(1-Z)^(DFY-2))*G1#+(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G5#+Z^DFX*(1-Z)^DFY*G6#)*ZZ*ZZ
2660 P2=-P20/DFX*EXP(G2#-G3#-G4#)
2670 RETURN
2680 '
2690 ' *** 合流型超幾何関数 ***
2700 '
2710 *CONFLUENT.HGF:' [Kummer]
2720 EPSL=1E-09
2730 G0#=0:G#=1
2740 T#=1:K=1
2750 WHILE ABS(G0#-G#)>EPSL
2760 T#=T#*A/C*Z/K
2770 G0#=G#
2780 G#=G#+T#
2790 K=K+1
2800 A=A+1
2810 C=C+1
2820 WEND
2830 G=G#
2840 RETURN
2850 '
2860 ' *** ガウス型超幾何関数 ***
2870 '
2880 *GAUSS.HGF:
2890 EPSL=1E-09
2900 G0#=0:G#=1
2910 T#=1:K=1
2920 WHILE ABS(G0#-G#)>EPSL
2930 T#=T#*A*B/C*Z/K
2940 G0#=G#
2950 G#=G#+T#
2960 K=K+1
2970 A=A+1
2980 B=B+1
2990 C=C+1
3000 WEND
3010 G=G#
3020 RETURN
3030 '
3040 ' *** 対数ガンマ関数 (HASTINGSの多項式近似) ***
3050 '
3060 *LOG.GAMMA:
3070 A1#=-.577191652#
3080 A2#= .988205891#
3090 A3#=-.897056937#
3100 A4#= .918206857#
3110 A5#=-.756704078#
3120 A6#= .482199394#
3130 A7#=-.193527818#
3140 A8#= .035868343#
3150 X=Z:G#=0
3160 IF X<1 THEN G#=-LOG(X):GOTO 3190
3170 WHILE X>2:X=X-1:G#=G#+LOG(X):WEND
3180 X=X-1
3190 G#=G#+LOG(1+X*(A1#+X*(A2#+X*(A3#+X*(A4#+X*(A5#+X*(A6#+X*(A7#+X*A8#))))))))
3200 L.GAMMA=G#
3210 G=G#
3220 RETURN
3230 '
3240 ' ** NORMAL DISTRIBUTION **
3250 '
3260 *NORMAL.PERCENT:
3270 XXX=-LOG(4*PP*(1-PP))
3280 UUN=SQR(XXX*(2.0611786#-5.7262204#/(XXX+11.640595#)))
3290 IF PP>.5 THEN UUN=-UUN
3300 RETURN
3310 '
3320 ' ** T-DISTRIBUTION **
3330 '
3340 *T.PERCENT:
3350 GOSUB *NORMAL.PERCENT
3360 UUN=ABS(UUN)
3370 UU2=UUN*UUN
3380 AA1=(UU2+1)/DF/4
3390 AA2=((5*UU2+16)*UU2+3)/96/DF/DF
3400 AA3=(((3*UU2+19)*UU2+17)*UU2-15)/384/DF/DF/DF
3410 AA4=((((79*UU2+776)*UU2+1482)*UU2-1920)*W-945)/92460!/DF/DF/DF/DF
3420 AA5=(((((27*UU2+339)*UU2+930)*UU2-1782)*W-765)*W+17955)/368640!/DF/DF/DF/DF/DF
3430 UUT=UUN*(1+AA1+AA2+AA3+AA4+AA5)
3440 IF PP>.5 THEN UUT=-UUT
3450 RETURN
3460 '
3470 ' ** F-DISTRIBUTION **
3480 '
3490 *F.PERCENT:
3500 IF DF1=1 THEN DF=DF2:PP=PP/2:GOSUB *T.PERCENT :UUF=UUT^2:PP=PP*2:RETURN
3510 IF DF2=1 THEN DF=DF2:PP=(1-PP)/2:GOSUB *T.PERCENT :UUF=1/UUT^2:PP=1-PP*2:RETURN
3520 IF DF1=2 THEN UUF=DF2/2*(PP^(-2/DF2)-1):RETURN
3530 IF DF2=2 THEN UUF=2/DF1/((1-PP)^(-2/DF1)-1):RETURN
3540 AA=2/9/DF1:BB=2/9/DF2:CC=1-AA:DD=1-BB
3550 GOSUB *NORMAL.PERCENT
3560 UUF=CC*DD+UUN*SQR(CC*CC*BB+DD*DD*AA-AA*BB*UUN*UUN)
3570 UUF=(UUF/(DD*DD-BB*UUN*UUN))^3
3580 RETURN
3590 '
3600 ' ** CHI-SQUARE DISTRIBUTION **
3610 '
3620 *CHI2.PERCENT:
3630 IF DF=1 THEN PP=PP/2:GOSUB *NORMAL.PERCENT :UUX=UUN*UUN:PP=PP*2:RETURN
3640 IF DF=2 THEN UUX=-2*LOG(PP):RETURN
3650 GOSUB *NORMAL.PERCENT
3660 UUX=2/(9*DF)
3670 UUX=1-UUX+UUN*SQR(UUX)
3680 UUX=UUX^3*DF
3690 RETURN
改良前のプログラムでは,χ2分布の下側5%点を計算しようとすると途中で計算が止まってしまいました.原因を調べてみると,χ2分布のパーセント点の近似値を求める段階にバグがあり,負であるはずの変数が非負になったためのエラートラップであることが判明しました.今回の修正ではその点をバグフィックスし,記述の見苦しい箇所を若干手直ししてあります.
===================================
【出力例】
χ2分布の下側5%点の計算精度
自由度 近似値 1次の反復法 数値表
1 .0039282 3.93214E-03 3.93214E-03
2 .102587 .102587 .102587
3 .327729 .351846 .351846
4 .689614 .710723 .710723
5 1.12725 1.14548 1.14548
6 1.61947 1.63538 1.63538
8 2.71996 2.73264 2.73264
10 3.92964 3.9403 3.9403
12 5.2167 5.22603 5.22603
15 7.25285 7.26094 7.26094
20 10.8438 10.8508 10.8508
30 18.4862 18.4927 18.4927
χ2分布の下側5%点の計算精度
自由度 2次の反復法 1次の反復法 数値表
1 3.93214E-03 3.93214E-03 3.93214E-03
2 .102587 .102587 .102587
3 .351846 .351846 .351846
4 .710723 .710723 .710723
5 1.14548 1.14548 1.14548
6 1.63538 1.63538 1.63538
8 2.73264 2.73264 2.73264
10 3.9403 3.9403 3.9403
12 5.22603 5.22603 5.22603
15 7.26094 7.26094 7.26094
20 10.8508 10.8508 10.8508
30 18.4927 18.4927 18.4927
===================================
【プログラムの改良】(漸化式の利用)
確率分布の計算において,これまで1次の微分を用いたニュートン法では発散するが,2次までの微分を用いたニュートン法では見事に収束するといったシーンに遭遇したことはありません.
a)十分な精度をもつ近似値が求められること
b)確率分布の関数自体が,数値計算上の振る舞いの悪い関数でない
というのがその理由であると考えられます.
2次のニュートン法では,2次導関数を計算するぶん計算量が増し,どうしても余分に所要時間がかかってしまうし,1次のニュートン法でも十分安定に収束しますから,確率分布の計算にとって,2次までの微分を用いたニュートン法は必要ないのかもしれません.しかし,もしも計算時間をほとんど要さずに,2次の微分値を計算することができたならば,話は別です.
前述したように,超幾何関数には微分・積分してもふたたび超幾何関数になるという特性があり,さらに,微分値を超幾何関数の漸化式を用いて計算すると,時間のかかる計算を回避することができます.2次までの微分を用いたニュートン法は超幾何関数向きの計算法になっているといえましょう.
1000 '
1010 ' ** 逐次計算 **
1020 '
1030 IF PROB$="N" THEN UUN=D0:GOSUB *NORMAL.PROB.HGF
1040 IF PROB$="X" THEN UUX=D0:GOSUB *CHI2.PROB.HGF
1050 IF PROB$="T" THEN UUT=D0:GOSUB *T.PROB.HGF
1060 IF PROB$="F" THEN UUF=D0:GOSUB *F.PROB.HGF
1070 F=P0-Q0:G=P1
1080 '
1090 H=P2:DI=G*G-F*H*2
1100 IF DI<0 THEN DELTA=-F/G:GOTO 1130
1110 IF G<0 THEN DELTA=F*2/(-G+SQR(DI)) ELSE DELTA=F*2/(-G-SQR(DI))
1120 '
1130 DD=D0+DELTA
1140 IF ABS(DD-D0)<EPSL THEN SW=1
1150 RETURN
1160 '
1170 ' ** NORMAL DISTRIBUTION **
1180 '
1190 *NORMAL.PROB.HGF:
1200 PI#=3.141592653589732#
1210 A0=1:C0=1.5
1220 A=A0:C=C0
1230 Z=UUN*UUN/2:GOSUB *CONFLUENT.HGF:G1#=G#
1240 P0=.5#+G1#*UUN*EXP(-UUN*UUN/2)/SQR(PI#*2)
1250 '
1260 A=A0:C=C0+1
1270 Z=UUN*UUN/2:GOSUB *CONFLUENT.HGF:G2#=G#*(A0/C0-1)+G1#
1280 P10=G1#*(1-UUN*UUN)+G2#*UUN*UUN
1290 P1=P10*EXP(-UUN*UUN/2)/SQR(PI#*2)
1300 '
1310 G3#=G1#*A0/Z-G2#*(C0+Z)/Z
1320 P20=-P10*UUN+G2#*UUN*(1-UUN*UUN)-G1#*UUN*2+G3#*UUN*UUN*UUN+G2#*UUN*2
1330 P2=P20*EXP(-UUN*UUN/2)/SQR(PI#*2)
1340 RETURN
1350 '
1360 ' ** CHI-SQUARE DISTRIBUTION **
1370 '
1380 *CHI2.PROB.HGF:
1390 A0=1:C0=1+DF/2
1400 A=A0:C=C0
1410 Z=UUX/2:GOSUB *CONFLUENT.HGF:G1#=G#
1420 Z=1+DF/2:GOSUB *LOG.GAMMA:G2#=G#
1430 'P0=G1#/G2#*(UUX/2)^(DF/2)*EXP(-UUX/2)
1440 P0=G1#/EXP(G2#)*(UUX/2)^(DF/2)*EXP(-UUX/2)
1450 '
1460 A=A0:C=C0+1
1470 Z=UUX/2:GOSUB *CONFLUENT.HGF:G3#=G#*(A0/C0-1)+G1#
1480 P10=DF/2*(UUX/2)^(DF/2-1)*G1#/2-(UUX/2)^(DF/2)*G1#/2+(UUX/2)^(DF/2)*G3#/2
1490 P1=P10/EXP(G2#)*EXP(-UUX/2)
1500 '
1510 G4#=G1#*A0/Z-G3#*(C0+Z)/Z
1520 P20=-P10/2+(DF/2*(DF/2-1)*(UUX/2)^(DF/2-2)-DF/2*(UUX/2)^(DF/2-1))*G1#/4+(DF/2*(UUX/2)^(DF/2-1)-(UUX/2)^(DF/2))*G3#/4+DF/2*(UUX/2)^(DF/2-1)*G3#/4+(UUX/2)^(DF/2)*G4#/4
1530 P2=P20/EXP(G2#)*EXP(-UUX/2)
1540 RETURN
1550 '
1560 ' ** T-DISTRIBUTION **
1570 '
1580 *T.PROB.HGF:
1590 DFX=DF/2:DFY=.5
1600 A0=DFX+DFY:B0=1:C0=DFX+1
1610 A=A0:B=B0:C=C0
1620 Z=DF/(DF+UUT*UUT):GOSUB *GAUSS.HGF:G1#=G#
1630 P0=G1#/DFX*Z^DFX*(1-Z)^DFY
1640 Z=DFX+DFY:GOSUB *LOG.GAMMA:G2#=G#
1650 Z=DFX :GOSUB *LOG.GAMMA:G3#=G#
1660 Z=DFY :GOSUB *LOG.GAMMA:G4#=G#
1670 P0=P0*EXP(G2#-G3#-G4#)
1680 P0=P0/2
1690 P0=1-P0
1700 '
1710 A=A0+1:B=B0:C=C0
1720 Z=DF/(DF+UUT*UUT):GOSUB *GAUSS.HGF:G5#=(G#-G1#)*A0/Z
1730 ZZ=-DF*UUT*2/(DF+UUT*UUT)^2
1740 P10=(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G1#+Z^DFX*(1-Z)^DFY*G5#
1750 P1=-P10*ZZ/DFX*EXP(G2#-G3#-G4#)/2
1760 '
1770 A=A0+1:B=B0-1:C=C0:G0#=1#
1780 G6#=-G#*A0*(C0-B0*2+(B0-A0-1)*Z)/Z/(1-Z)-G0#*A0*(B0-C0)/Z/(1-Z)-G5#*C0/Z
1790 ZZZ=-DF*2*(DF-UUT*UUT*3)/(DF+UUT*UUT)^3
1800 P20=P10*ZZZ+((DFX*(DFX-1)*Z^(DFX-2)*(1-Z)^DFY-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)+Z^DFX*DFY*(DFY-1)*(1-Z)^(DFY-2))*G1#+(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G5#+Z^DFX*(1-Z)^DFY*G6#)*ZZ*ZZ
1810 P2=-P20/DFX*EXP(G2#-G3#-G4#)/2
1820 RETURN
1830 '
1840 ' ** F-DISTRIBUTION **
1850 '
1860 *F.PROB.HGF:
1870 DFX=DF2/2:DFY=DF1/2
1880 A0=DFX+DFY:B0=1:C0=DFX+1
1890 A=A0:B=B0:C=C0
1900 Z=DF2/(DF2+DF1*UUF):GOSUB *GAUSS.HGF:G1#=G#
1910 P0=G1#/DFX*Z^DFX*(1-Z)^DFY
1920 Z=DFX+DFY:GOSUB *LOG.GAMMA:G2#=G#
1930 Z=DFX :GOSUB *LOG.GAMMA:G3#=G#
1940 Z=DFY :GOSUB *LOG.GAMMA:G4#=G#
1950 P0=P0*EXP(G2#-G3#-G4#)
1960 P0=1-P0
1970 '
1980 A=A0+1:B=B0:C=C0
1990 Z=DF2/(DF2+DF1*UUF):GOSUB *GAUSS.HGF:G5#=(G#-G1#)*A0/Z
2000 ZZ=-DF2*DF1/(DF2+DF1*UUF)^2
2010 P10=(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G1#+Z^DFX*(1-Z)^DFY*G5#
2020 P1=-P10*ZZ/DFX*EXP(G2#-G3#-G4#)
2030 '
2040 A=A0+1:B=B0-1:C=C0:G0#=1#
2050 G6#=-G#*A0*(C0-B0*2+(B0-A0-1)*Z)/Z/(1-Z)-G0#*A0*(B0-C0)/Z/(1-Z)-G5#*C0/Z
2060 ZZZ=-DF2*DF1*DF1*2/(DF2+DF1*UUF)^3
2070 P20=P10*ZZZ+((DFX*(DFX-1)*Z^(DFX-2)*(1-Z)^DFY-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)-DFX*Z^(DFX-1)*DFY*(1-Z)^(DFY-1)+Z^DFX*DFY*(DFY-1)*(1-Z)^(DFY-2))*G1#+(DFX*Z^(DFX-1)*(1-Z)^DFY-Z^DFX*DFY*(1-Z)^(DFY-1))*G5#+Z^DFX*(1-Z)^DFY*G6#)*ZZ*ZZ
2080 P2=-P20/DFX*EXP(G2#-G3#-G4#)
2090 RETURN
プログラムの全文を載せると長くなるので,改良部分だけを掲載しました.ここで用いた漸化式については難しいので掲載しませんが,漸化式の計算では,「電子通信工学のための特殊関数とその応用」(奥井重彦著:森北出版)を参考にしました.
確率分布には様々の特殊関数が用いられていますが,なかでもガンマ関数・ベータ関数などは必須項目であり,さらに非心分布ではベッセル関数・超幾何関数などの理解も必要になります.しかし,これらの特殊関数はプロの統計研究者にとっても馴染みの薄いものであり,ましてや一般のひとにとって(無論,私にとっても)とっつきにくいものです.「電子通信工学のための特殊関数とその応用」は,一松信「特殊関数入門」森北出版よりもプラクティカルな面に注力していて,現在,私の仕事に最も役立っている本となっています.特殊関数についていろいろな話題を交えながらわかりやすく解説しており,「電子通信工学のための・・・」と銘打っていますが,数理統計学における方法的基礎の副読本としてもぜひともお勧めしたい書籍です.
なお,ベキ級数展開版でなく,連分数展開版として使いたい場合は,
a)1230・1270・1410・1470行
gosub *confluent.hgf → gosub *confluent.hgf1
b)1620・1720・1900・1990行
gosub *gauss.hgf → gosub *gauss.hgf1
と変更して下さい.
2100 '
2110 ' *** 合流型超幾何関数の連分数展開 ***
2120 '
2130 *CONFLUENT.HGF1:' 1F1(1,c,x)
2140 NZ=50
2150 G#=0
2160 FOR ID=NZ TO 1 STEP -1
2170 EVEN#=ID/(C+2*ID-1)/(C+2*ID-2)
2180 ODD#=-(C+ID-1)/(C+2*ID)/(C+2*ID-1)
2190 G#=ODD#*Z/(1+G#)
2200 G#=EVEN#*Z/(1+G#)
2210 NEXT ID
2220 G#=-Z/C/(1+G#)
2230 G#=1/(1+G#)
2240 RETURN
2250 '
2260 ' *** ガウス型超幾何関数の連分数展開 ***
2270 '
2280 *GAUSS.HGF1:' 2F1(a,1,c,x)
2290 NZ=50
2300 G#=0
2310 FOR ID=NZ TO 1 STEP -1
2320 ODD#=-(A+ID-1)*(C+ID-2)/(C+2*ID-2)/(C+2*ID-3)
2330 EVEN#=-ID*(C-A+ID-1)/(C+2*ID-1)/(C+2*ID-2)
2340 G#=EVEN#*Z/(1+G#)
2350 G#=ODD#*Z/(1+G#)
2360 NEXT ID
2370 G#=1/(1+G#)
2380 RETURN
===================================
【補】非線形方程式の解法
(3)微分係数の差分近似
ニュートン法やベイリー法では元の方程式の導関数の計算が必要になりますが,方程式の形が複雑な場合には導関数から解析的に勾配を求めることが大変になってきます.その場合には,xに対して微小の幅で数値差分をとり,微分式の代用とします.
1次微分係数f’(x)の符号はもとの関数f(x)の増減と関連し,2次微分係数f”(x)の符号はもとの関数の凹凸(曲率)と関連していることはご存じと思いますが,数値差分(数値微分)というのは,例えば,y=x^2を微分してy’=2xのように解析的に求めるのではなく,xのある点における関数y=f(x)の傾きを差分近似を用いて数値的に求める数値解法をいいます.
たとえば,数値差分公式(中心差分)には次のようなものがあります.
f’(x)≒{f(x+h)−f(x−h)}/2h
f’(x)≒{−f(x+2h)+8f(x+h)−8f(x−h)+f(x−2h)}/12h
f”(x)≒{f(x+h)−2f(x)+f(x−h)}/h^2
このように,数値計算的に勾配を求めると方程式の形が複雑であっても確実に根が求まる利点があります.
コンピュータを用いた数値解析では微分係数f’(x)を
f’(x)≒{f(x+h)−f(x)}/h・・・・・・(1)
f’(x)≒{f(x)−f(x−h)}/h・・・・・・(2)
f’(x)≒{f(x+h)−f(x−h)}/2h・・・(3)
で差分近似して計算するほうが取り扱いが容易になります.いずれも導関数を差分商で置き換えるのですが,(1)を前進差分近似,(2)を後退差分近似,(3)を中心差分近似と呼びます.
一般には,
f’(x)≒α{f(x+h)−f(x)}/h+β{f(x)−f(x−h’)}/h’
0≦α,β≦1,α+β=1,h→0,h’→0
によって,f’(x)の近似式が与えられます.前進差分近似,後退差分近似,中心差分近似はh=h’で,それぞれ
(1)α=1,β=0
(2)α=0,β=1
(3)α=1/2,β=1/2
の場合に相当します.
幅hが0に近づくとき割線は接線に近づきますから,差分を使うとき,hは原理的には小さいほど理想的ですが,あまりにも小さいと差分の中に占める数値計算誤差の比重が大きくなり,かえって精度が悪くなってしまいます.関数fの性質とhの取り方によって精度は決まりますが,誤差について次のように検討してみましょう.
連続で何度でも微分可能な関数y=f(x)をテイラー展開すると,
f(x+h)=f(x)+f’(x)h+1/2!f”(x)h^2+1/3!f'''(x)h^3+・・・ (4)
となります.したがって,
f’(x)={f(x+h)−f(x)}/h−{1/2f”(x)h+1/6f'''(x)h^2+・・・}
より,1次微分係数は近似的に前進差分(1)として求められます.この公式の誤差は{1/2f”(x)h+1/6f'''(x)h^2+・・・}の部分ですから,hにほぼ比例すると考えることができるため,{・・・}括弧の部分をO(h)と表わします.
f’(x)={f(x+h)−f(x)}/h+O(h)
Oはランダウの記号で,O(h)はhの1次のオーダーという意味です.
また,(4)のhに−1を掛けると
f(x−h)=f(x)−f’(x)h+1/2!f”(x)h^2−1/3!f'''(x)h^3+・・・ (5)
となります.前進差分と同様にして
f’(x)={f(x)−f(x−h)}/h+O(h)
すなわち,後退差分公式(2)が成り立ちます.(1),(2)とも誤差はhのオーダーであることがわかります.
次に,(4)から(5)を引くと
f(x+h)−f(x−h)=2f’(x)h+1/3f'''(x)h^3+・・・ (6)
より
f’(x)={f(x+h)−f(x−h)}/2h−{1/6f'''(x)h^2+・・・}
={f(x+h)−f(x−h)}/2h+O(h^2)
となり,中心差分近似の打ち切り誤差はh^2に比例します.このことから,中心差分は前進差分・後退差分より平均的な打ち切り誤差が少なく,精度が高いことが理解されます.ただし,関数値の計算回数は余計にかかります.
次に,2次微分係数ですが,前進差分近似,後退差分近似,中心差分近似のそれぞれに対応した数値微分を作ることが可能です.例えば,中心差分近似式(3)を用いると
f”(x)={f’(x+h)−f’(x−h)}/2h
={f(x+2h)−f(x))/4h^2−(f(x)−f(x−2h)}/4h^2
={f(x+2h)−2f(x)+f(x−2h)}/4h^2
ここで改めて2hをhと置きかえると,2次微分係数の差分近似式は
f”(x)={f(x+h)−2f(x)+f(x−h)}/h^2
のように求まります.この式の誤差は(4)と(5)を加えると
f(x+h)+f(x−h)=2f(x)+f”(x)h^2+1/12f''''(x)h^4+・・・
より
f”(x)={f(x+h)−2f(x)+f(x−h)}/h^2+O(h^2)
と評価することができます.
いま,中心差分近似式f”(x)={f(x+2h)−2f(x)+f(x−2h)}/4h^2を採用すると
f'''(x)=1/2h{f”(x+h)−f”(x−h)}
=(1/2h)^3{f(x+3h)−3f(x+h)+3f(x−h)−f(x−3h)}+O(h^2)
さらに,
f''''(x)=(1/2h)^4{f(x+4h)−4f(x+2h)+6f(x)−4f(x−2h)+f(x−6h)}+O(h^2)
が得られます.4次微分係数の差分近似式では2hをhと置きかえることができます.
一階中心差分近似式,二階中心差分近似式にはそれぞれに係数[1,−1],[1,−2,1]がはいっていましたが,それ以上の高階差分近似式にも,[1,−3,3,−1],[1,−4,6,−4,1]など二項係数 nCk が符号を交代させた形で入っていることが示されます.これは数学的帰納法を用いて簡単に証明できます.一般式の形で書くこともできますが,読者の演習問題にしておきます.
また,中心差分近似式f”(x)={f(x+h)−2f(x)+f(x−h)}/h^2を採用した場合の3次微分係数と4次微分係数の差分近似式は,
f'''(x)=1/2h{f”(x+h)−f”(x−h)}
=1/2h^3{f(x+2h)−2f(x+h)+2f(x−h)−f(x−2h)}+O(h^2)
f''''(x)=1/2h{f'''(x+h)−f'''(x−h)}
=1/4h^4{f(x+3h)−2f(x+2h)−f(x+h)+4f(x)−f(x−h)−2f(x−2h)+f(x+3h)}+O(h^2)
となることも知っておくべきです.いずれにせよ,中心差分近似式(3)を用いた場合の誤差はO(h^2)になっています.
なお,導関数を近似する差分式で,必要とする精度をもつ公式は原理的には無数に導くことができます.たとえば,O(h^2)の精度をもつ3点差分公式
f’(x)={3f(x)−4f(x−h)+f(x−2h)}/2h+O(h^2)
などがそれに相当します.また,高精度の差分公式としては4点差分公式
f’(x)=1/12h{−f(x+2h)+8f(x+h)−8f(x−h)+f(x−2h)}+O(h^4)
6点差分公式
f’(x)=1/60h{f(x+3h)−9f(x+2h)+45f(x+h)−45f(x−h)+9f(x−2h)−f(x−3h)}+O(h^6)
などがあげられます.
導関数の計算をコンピュ−タで行う場合,連続な変化は扱えないので,小さな変化を決めて離散的に解く数値解法が主体になります.差分近似式(数値微分式)では元の方程式の形が複雑であっても確実に勾配の求まる利点があり,コンピュータを用いた数値解析では,解析的な微分式よりも差分近似式が多用されます.そのため,差分法(FDM)は微分方程式の数値解法,有限要素法(FEM),境界要素法(BEM)にとって欠かせない知識になっています.
コンピュータ計算では多くの場合,微分方程式や積分を差分解法によって解きますが,この手法は詰まるところ,アナログのデジタル変換による解法といい換えることができます.そのため,微分方程式を正しく近似している差分方程式を使ったとしても,その解は微分方程式の解の近似になるとは限らないという矛盾を生じ,微分方程式の解とはまったく違う性質がでてくることがあります.したがって,無数にある差分方程式から安定なものを選び出し,元の微分方程式の解の性質を保存するように差分化することが必要になってきます.
最後にもう一度,中心差分近似による1次と2次の微分係数の近似式を,誤差まで含めて示しておきます.
f’(x)={f(x+h)−f(x−h)}/2h+O(h^2)
f”(x)={f(x+h)−2f(x)+f(x−h)}/h^2+O(h^2)
(4)2分法と割線法
さらに,微分も差分も必要としない方法が,ここで紹介する逐次2分法や割線法(線形逆補間法)です.
2分法や割線法では最初に解をはさむ2つの近似値が必要です.f(x0)=0となる真の値x0をはさむような近傍の値x1,x2を入力すると,f(x1)とf(x2)の符号が異なるので,根x0は区間(x1,x2)の中に必ず存在します.2分法では中点x3=(x1+x2)/2,割線法ではx軸との交点x3={x1f(x2)−x2f(x1)}/{f(x2)−f(x1)}でのf(x3)の符号を調べてみて,もしf(x1)とf(x3)が同符号ならばx3を新しいx1として,そうでなければx3を新しいx2として計算を繰り返します.
逐次2分法は1次収束,割線法は1.618次収束なのでニュートン法の2次収束,ベイリー法の3次収束に比べ収束の遅い漸近近似法ですが,これを続けていけば根cの存在する区間は毎回狭められ絞り込まれていき,必ず真の値に収束することになります.導関数の計算が困難であったり,時間がかかるならば2分法や割線法を使ったほうがよいでしょう.
(5)非線形連立方程式の解法
以上は1変数の非線形方程式f(x)=0の解法でしたが,多変数の場合でも考え方は同じで,前節のニュートン・ラプソン法Δx=−f(x)/f’(x)は非線形連立方程式の解を求める場合にも拡張することができます.
非線形連立方程式は,
x=(x1,x2,・・・,xn)
f1(x1,x2,・・・,xn)=0
f2(x1,x2,・・・,xn)=0
・・・・・・・・・・・・・・・
fn(x1,x2,・・・,xn)=0
で与えられますが,ベクトルを用いるとf(x)=0のように書けますから,多変数関数においてはΔxとf(x)はベクトルに,f’(x)はヤコビ行列と呼ばれる行列になるだけの違いです.
2変数の場合において具体的に考えてみることにしましょう.例として,2元非線形連立方程式
f(x,y)=0
g(x,y)=0
の2つの変数x,yに関して近似解(x0,y0)がわかっている場合,その解の精度を上げるニュートン・ラプソン法について紹介します.より改良された近似解をx=x0+Δx,y=y0+Δyとします.この連立方程式ではパラメータx,yに関して非線形ですので,パラメータの近似値x0,y0の回りで1次までのテイラー展開を行ない線形化します.
このとき,テイラー展開の1次の項までをとると,
f(x,y)=f(x0,y0)+fx(x0,y0)Δx+fy(x0,y0)Δy
g(x,y)=g(x0,y0)+gx(x0,y0)Δx+gy(x0,y0)Δy
ここで,f(x,y)はf(x0,y0)に比べて,g(x,y)はg(x0,y0)に比べて小さいと考えることができますから,これを無視して整理するとΔx,Δyに関しての線形方程式
fxΔx+fyΔy=−f
gxΔx+gyΔy=−g
が得られます.ここで行列式
J=|fx fy|
|gx gy|
はヤコビアンと呼ばれるものです.Δx,Δyについて解くと
Δx=(fyg−gyf)/(fxgy−gxfy)
Δy=(fgx−gfx)/(fxgy−gxfy)
となり,x,yの漸近近似が可能になります.
3元非線形連立方程式
f(x,y,z)=0
g(x,y,z)=0
h(x,y,z)=0
についても同様であり,
fxΔx+fyΔy+fzΔz=−f
gxΔx+gyΔy+gzΔz=−g
hxΔx+hyΔy+hzΔz=−h
です.3変数の場合のヤコビアンは,
|fx fy fz|
J=|gx gy gz|
|hz hy hz|
と書くことができます.ヤコビアンはヤコビの名をとどめる行列式です.韻をふんだ名前ではガリレオ・ガリレイが有名ですが,ヤコビ・ヤコブというのもその類です.ヤコビが先鞭をつけた関数行列式はヘッセなどに引き継がれ,解析幾何学の面でたびたび利用され発展しました.ヘッセにもヘシアンという彼の名をとどめる行列式があり,2変数の場合は,
H=|fxx fxy|
|fyx fyy|
3変数の場合は,
|fxx fxy fxz|
H=|fyx fyy fyz|
|fzx fzy fzz|
になります.
===================================