■楕円近似について(その3)

 (その2)に掲載したプログラムは,その後,いろいろな使われ方をしていることがわかった.ところが,先日,このプログラムに対する苦情が寄せられてきた.データを処理したところ,半径P(1)がマイナスの方向に発散していき,エラーで止まってしまうというものである.
 
 最小2乗法ソフト「耕太郎」本体の方には,たとえば,半径のように負にならないパラメータに対して,非負なる制約条件をつけたフィッティング機能が付いているし,初期値がかなりずれていても安定に収束させるための計算アルゴリズムも装備しているのだが,(その2)に載せたプログラムではそれらのサブルーチンを省いている.
 
 当初はそのためのエラーかと思っていたら,どうもそうではないらしいことが判明した.添付データを見たところ,そのデータは楕円の弧のほんの一部分だけにすぎなかったのである.メールを交換してみると,楕円のデータは全周にわたってある場合と中心線より片側に集中する場合があり,現場で特に必要としているのは後者の方であるということがわかった.
 
 しかるに,HPに掲載した非線形最小2乗法のプログラムの初期値サブルーチンは,ほぼ全周にわたってデータ点が採取されているときの設定になっているので,そのサブルーチンを使う限り,苦情にあげたようなエラーは避けられない.
 
 対策としては,
  (1)パラメータの値を初期値サブルーチンを使わないで,直接入力する
  (2)初期値に関わらないでパラメータを計算できる線形最小2乗計算を用いて計算してから,その値を初期値として非線形最小2乗計算に移る
であるが,(1)のように自動計算してくれないようではユーザーの手を煩わせることになり,あまり推奨できない.最も忌み嫌われるプログラムなのである.
 
 そこで,今回のコラムではデータが片側あるいは弧の一部に集中する場合であっても,手入力なしに自動計算できるようにプログラムを書き換えてみることにした.
 
===================================
 
[1]あてはめ例
 
 
 なお,この計算例では,P(1)<P(2)となりましたが,プログラム上はどちらかを長半径にどちらかを短半径に特定しているわけではなく,大きい方が長半径ということであって,P(1)<P(2)となっても実害は生じません.
 
===================================
 
[2]プログラムの解説
 
 中心が原点ではなく,しかも,傾きのある2次元楕円は,5つのパラメータをもつ曲線
  f(x,y)=a1x^2 +a2xy+a3y^2+a4x+a5y−1=0
の形に書けます.この形であれば,多変量の線形最小2乗法が適用可能です.非線形のプログラムでも線形最小2乗法は解けるのですが,その逆は不可能です.
 
 一方,楕円の基本情報,すなわち,長半径・短半径をa,b,長軸とx軸のなす角度をθ,楕円の中心を(x0,y0)として,楕円モデル式を
  {(x−x0)cosθ+(y−y0)sinθ}^2/a^2+{(x−x0)sinθ−(y−y0)cosθ}^2/b^2=1
とすると,未定係数が三角関数の中に含まれているため,どのように変形してもパラメータに関して線形とはなりません.そのため,非線形最小2乗法によるあてはめが必要になります.
 
 しかし,このモデル式では,楕円を媒介変数表示の形に表せるので,描画が短時間で済むようになりますし,現場からの要求である楕円基本情報
  a,b,θ,x0,y0
とその推定誤差
  Δa,Δb,Δθ,Δx0,Δy0
を求めることにも応えることができるのです.
 
 したがって,まず最初に
  f(x,y)=a1x^2 +a2xy+a3y^2+a4x+a5y−1
に対して,多変量線形最小2乗法によるあてはめを行い,そのあとで,
  a1,a2,a3,a4,a5 → a,b,θ,x0,y0
の変換式を利用して,
  {(x−x0)cosθ+(y−y0)sinθ}^2/a^2+{(x−x0)sinθ−(y−y0)cosθ}^2/b^2=1
の形に直してから,パラメータの推定誤差を求め,描画を行うという2ステップの計算方法が考えられます.
 
 そのため,これまでの初期値サブルーチン(2530行〜2750行)を廃止して,主に8520行以下を新規追加しました.パラメータの計算は,線形最小2乗法が済んだ時点でほぼ収束しているのですが,さらに時間をかけて,パラメータの誤差計算に移ります.計算に時間を要するのですが,非線形最小2乗法をあてはめのためにではなく,主にパラメータの誤差値を求めるために用いるという贅沢な方法ともいえるでしょう.
 
 このような書き換えによって,弧の一部しかないデータの場合でも安定に収束するようになり,計算が発散するのを未然に防ぐことができるようになりました.なお,プログラムの簡単な書き換えにより,楕円面のあてはめ問題も解くことができるようになります.
 
===================================
 
[3]プログラム
 
1000 '
1010 ' **** elliptic approximation ****
1020 '             2002/08/23 (C) サトウ イクロウ
1030 SCREEN 3,0:CONSOLE ,,0,1
1040 CLS 3:WIDTH 80,25:COLOR 6
1050 GOSUB *INITIALIZE
1060 GOSUB *READ.DATA
1070 GOSUB *INIT.VAL
1080 GOSUB *EXECUTION
1090 GOSUB *SCATTER.DIAGRAM
1100 GOSUB *REPORT
1110 END
1120 '
1130 ' *** 初期設定 ***
1140 '
1150 *INITIALIZE:
1160 M=5:' No. of parameters
1170 DIM P(M),W(M)
1180 DIM A(M)
1190 DIM P0(M),P1(M),DP(M)
1200 DIM AZ(M,M),BZ(M,M)
1210 DIM HESSE(M,M)
1220 DIM SD(M),SE(M)
1230 DIM COV(M,M)
1240 '
1250 NV=2:' No. of independent variables
1260 DIM X(NV)
1270 DIM AVE(NV),DEV(NV),SEM(NV)
1280 DIM XMAX(NV),XMIN(NV)
1290 FOR J=0 TO NV
1300  XMAX(J)=-1E+10:XMIN(J)=1E+10
1310 NEXT J
1320 '
1330 RX=.7:RY=.8:BOX=1:KIND=1:POWER=0
1340 IX=.7:IY=.8:MARK=1:CLR=2:DRAW.COLOR=4
1350 TXT.COLOR=6:GRP.COLOR=5:REF.COLOR=6
1360 SCALE.KIND=1:PLOT=1
1370 PI=3.14159
1380 'JX=.709:JY=1
1390 JX=1  :JY=1
1400 RX=IX*JX:RY=IY*JY
1410 '
1420 FORM$="(((X(1)-P(4))*COS(P(3))+(X(2)-P(5))*SIN(P(3)))/P(1))^2+(((X(1)-P(4))*SIN(P(3))-(X(2)-P(5))*COS(P(3)))/P(2))^2-1"
1430 RETURN
1440 '
1450 ' *** DEFINED EQUATION ***
1460 '
1470 *DEFINE.FORMULA:
1480 DEF FNY(X)=(((X(1)-P(4))*COS(P(3))+(X(2)-P(5))*SIN(P(3)))/P(1))^2+(((X(1)-P(4))*SIN(P(3))-(X(2)-P(5))*COS(P(3)))/P(2))^2-1
1490 RETURN
1500 '
1510 *DEFINE.FORMULA2:
1520 ON J GOSUB *J1,*J2,*J3,*J4,*J5
1530 RETURN
1540 '
1550 *J1:
1560 DEF FNJ(X)=-2*((X(1)-P(4))*COS(P(3))+(X(2)-P(5))*SIN(P(3)))^2/P(1)^3
1570 RETURN
1580 *J2:
1590 DEF FNJ(X)=-2*((X(1)-P(4))*SIN(P(3))-(X(2)-P(5))*COS(P(3)))^2/P(2)^3
1600 RETURN
1610 *J3:
1620 DEF FNJ(X)=2*((X(1)-P(4))*COS(P(3))+(X(2)-P(5))*SIN(P(3)))*(-(X(1)-P(4))*SIN(P(3))+(X(2)-P(5))*COS(P(3)))/P(1)^2+2*((X(1)-P(4))*SIN(P(3))-(X(2)-P(5))*COS(P(3)))*((X(1)-P(4))*COS(P(3))+(X(2)-P(5))*SIN(P(3)))/P(2)^2
1630 RETURN
1640 *J4:
1650 DEF FNJ(X)=-2*((X(1)-P(4))*COS(P(3))+(X(2)-P(5))*SIN(P(3)))*COS(P(3))/P(1)^2-2*((X(1)-P(4))*SIN(P(3))-(X(2)-P(5))*COS(P(3)))*SIN(P(3))/P(2)^2
1660 RETURN
1670 *J5:
1680 DEF FNJ(X)=-2*((X(1)-P(4))*COS(P(3))+(X(2)-P(5))*SIN(P(3)))*SIN(P(3))/P(1)^2+2*((X(1)-P(4))*SIN(P(3))-(X(2)-P(5))*COS(P(3)))*COS(P(3))/P(2)^2
1690 RETURN
1980 '
1990 ' *** データ読み込み ***
2000 '
2010 *READ.DATA:
2020 CLS 3
2030 RESTORE *D
2040 READ N1
2050 'DFILE$="DATA01.TXT"
2060 'OPEN DFILE$ FOR INPUT AS #1
2070 'INPUT #1,N1
2080 '
2090 DIM XX1(NV,N1),YH(N1),WT(N1)
2100 DIM Y1(N1),E1(N1)
2110 DIM Z1(N1)
2120 DIM JACOBI(M,N1)
2130 FOR J=1 TO N1:WT(J)=1:NEXT J
2140 '
2150 FOR I=1 TO N1
2160  FOR J=1 TO NV
2170   READ XX1(J,I)
2180  'INPUT #1,XX1(J,I)
2190  NEXT J
2200 NEXT I
2210 'CLOSE #1
2220 '
2230 PRINT "ただいまデータの取り込み中"
2240 FOR I=1 TO N1
2250 PRINT "*";
2260 Y1(I)=0
2270 Z1(I)=1
2280 X(0)=Y1(I)
2290 FOR J=1 TO NV
2300  X(J)=XX1(J,I)
2310 NEXT J
2320 GOSUB *CALCULATE
2330 NEXT I
2340 '
2350 FOR J=0 TO NV
2360  SS=DEV(J)-AVE(J)*AVE(J)/N1
2370  DEV(J)=SQR(SS/(N1-1))
2380  SEM(J)=DEV(J)/SQR(N1)
2390  AVE(J)=AVE(J)/N1
2400 NEXT J
2410 RETURN
2420 '
2430 ' *** CALCULATE ***
2440 '
2450 *CALCULATE:
2460 FOR J=0 TO NV
2470  IF XMAX(J)<X(J) THEN XMAX(J)=X(J)
2480  IF XMIN(J)>X(J) THEN XMIN(J)=X(J)
2490  AVE(J)=AVE(J)+X(J)
2500  DEV(J)=DEV(J)+X(J)*X(J)
2510 NEXT J
2520 RETURN
2530 '
2540 ' ** 初期値 **
2550 '
2560 '*INIT.VAL:
2570 X0=0:Y0=0
2580 FOR I=1 TO N1
2590  X=XX1(1,I):Y=XX1(2,I)
2600  X0=X0+X
2610  Y0=Y0+Y
2620 NEXT I
2630 X0=X0/N1:Y0=Y0/N1
2640 P(4)=X0:P(5)=Y0
2650 '
2660 MAX=-1E+10:MIN=1E+10
2670 FOR I=1 TO N1
2680  X=XX1(1,I):Y=XX1(2,I)
2690  D=SQR((X-X0)^2+(Y-Y0)^2)
2700  IF MAX<D THEN MAX=D:XMAX=X-X0:YMAX=Y-Y0
2710  IF MIN>D THEN MIN=D
2720 NEXT I
2730 P(1)=MAX:P(2)=MIN
2740 IF XMAX=0 THEN P(3)=PI/2 ELSE P(3)=ATN(YMAX/XMAX)
2750 RETURN
2760 '
2770 ' *** 非線形最小2乗法 ***
2780 '
2790 *EXECUTION:
2800 PRINT:PRINT "ただいま計算中"
2810 GOSUB *GAUSS.NEWTON
2820 GOSUB *FINAL
2830 RETURN
2840 '
2850 ' *** GAUSS-NEWTON METHOD ***
2860 '
2870 *GAUSS.NEWTON:
2880 LMAX=50
2890 LOOP=0
2900 GOSUB *RESIDUAL:SO=SS
2910 GOSUB *TEMPORARY
2920 '
2930 GOSUB *JACOBIAN
2940 GOSUB *HESSIAN
2950 FOR I=1 TO M:P1(I)=P(I):NEXT I
2960 GOSUB *MARQUARDT
2970 GOSUB *UPDATE
2980 GOSUB *TRANSFORM
2990 '
3000 IF SN<SO THEN 3020
3010 FOR I=1 TO M:DP(I)=DP(I)/2:NEXT I:GOSUB *TRANSFORM:' [DAMPING]
3020 GOSUB *CONVERGENCE:IF SW=0 THEN RETURN
3030 SO=SN:IF LOOP<LMAX THEN 2930
3040 RETURN
3050 '
3060 ' ** X **
3070 '
3080 *JACOBIAN:
3090 FOR I=1 TO N1
3100  FOR V=1 TO NV:X(V)=XX1(V,I):NEXT V
3110  FOR J=1 TO M
3120   GOSUB *DEFINE.FORMULA2
3130   JACOBI(J,I)=FNJ(X)
3140  NEXT J
3150 NEXT I
3160 GOSUB *JACOBIAN.SUB
3170 RETURN
3180 '
3190 ' ** Y **
3200 '
3210 *JACOBIAN.SUB:
3220 FOR I=1 TO N1
3230  FOR V=1 TO NV:X(V)=XX1(V,I):NEXT V
3240  GOSUB *DEFINE.FORMULA:YH=FNY(X)
3250  E1(I)=Y1(I)-YH
3260  YH(I)=YH
3270 NEXT I
3280 '
3290 ' ** XT*Y **
3300 '
3310 FOR J=1 TO M
3320  S=0
3330  FOR I=1 TO N1
3340   S=S+JACOBI(J,I)*E1(I)*WT(I)
3350  NEXT I
3360  W(J)=S
3370 NEXT J
3380 RETURN
3390 '
3400 ' ** XT*X **
3410 '
3420 *HESSIAN:
3430 FOR M1=1 TO M
3440  FOR M2=M1 TO M
3450   S=0
3460   FOR I=1 TO N1
3470    S=S+JACOBI(M1,I)*JACOBI(M2,I)*WT(I)
3480   NEXT I
3490   HESSE(M1,M2)=S:HESSE(M2,M1)=S
3500  NEXT M2
3510 NEXT M1
3520 NZ=M
3530 RETURN
3540 '
3550 ' ** MARQUARDT **
3560 '
3570 *MARQUARDT:
3580 FOR I=1 TO M
3590  FOR J=1 TO M:AZ(I,J)=HESSE(I,J):NEXT J
3600 NEXT I
3610 RETURN
3620 '
3630 ' ** UPDATE **
3640 '
3650 *UPDATE:
3660 GOSUB *INVERSE:' (XT*X)^(-1)
3670 GOSUB *UPDATE.SUB
3680 RETURN
3690 '
3700 ' ** (XT*X)^(-1)*XT*Y **
3710 '
3720 *UPDATE.SUB:
3730 FOR J=1 TO M
3740  S=0
3750  FOR K=1 TO M
3760   S=S+BZ(J,K)*W(K)
3770  NEXT K
3780  DP(J)=S
3790 NEXT J
3800 RETURN
3810 '
3820 ' ** TRANSFORM of PARAMETERS **
3830 '
3840 *TRANSFORM:
3850 FOR I=1 TO M
3860  P(I)=P1(I)+DP(I)
3870 NEXT I
3880 GOSUB *RESIDUAL:SN=SS
3890 RETURN
3900 '
3910 ' ** SUM of RESIDUALS **
3920 '
3930 *RESIDUAL:
3940 SS=0
3950 FOR K=1 TO N1
3960  FOR V=1 TO NV:X(V)=XX1(V,K):NEXT V
3970  GOSUB *DEFINE.FORMULA:YH=FNY(X)
3980  SS=SS+WT(K)*(Y1(K)-YH)^2
3990 NEXT K
4000 RETURN
4010 '
4020 ' *** CHECK of CONVERGENCE ***
4030 '
4040 *CONVERGENCE:
4050 'EPS=.0001
4060 EPS=.001
4070 SW=0
4080 IF ABS((SN-SO)/SO)>EPS THEN SW=1
4090 GOSUB *TEMPORARY
4100 RETURN
4110 '
4120 ' *** TEMPORARY OUTPUT ***
4130 '
4140 *TEMPORARY:
4150 LOOP=LOOP+1
4160 CLS 3
4170 PRINT "LOOP=";LOOP
4180 PRINT
4190 PRINT "PARAMETERS: "
4200 FOR I=1 TO M
4210  PRINT "P(";I;")=";P(I)
4220 NEXT I
4230 PRINT
4240 PRINT "RESIDUALS=";SS
4250 RETURN
4260 '
4270 ' *** FINAL OUTPUT ***
4280 '
4290 *FINAL:
4300 CLS 3
4310 PRINT "LOOP=";LOOP
4320 PRINT
4330 PRINT "PARAMETERS: "
4340 FOR I=1 TO M
4350  PRINT "P(";I;")=";P(I)
4360 NEXT I
4370 PRINT
4380 PRINT "RESIDUALS=";SN
4390 '
4400 GOSUB *PROPAGATION
4410 PRINT
4420 PRINT "何かキーを押してください"
4430 WHILE INKEY$="":WEND
4440 RETURN
4450 '
4460 ' ** INVERSE MATRIX ( AZ==>BZ ) **
4470 '
4480 *INVERSE:' [GAUSS-JORDAN]
4490 FOR I=1 TO NZ
4500  FOR J=1 TO NZ:BZ(I,J)=0:NEXT J
4510  BZ(I,I)=1
4520 NEXT I
4530 FOR I=1 TO NZ
4540  IZ=I
4550  IF AZ(I,I)=0 THEN 4560 ELSE 4620
4560  IZ=IZ+1:IF IZ>NZ THEN RZ=1:RETURN
4570  IF AZ(IZ,I)=0 THEN 4560
4580  FOR J=1 TO NZ
4590   SWAP AZ(I,J),AZ(IZ,J)
4600   SWAP BZ(I,J),BZ(IZ,J)
4610  NEXT J
4620  AII=AZ(I,I)
4630  FOR J=1 TO NZ
4640   AZ(I,J)=AZ(I,J)/AII
4650   BZ(I,J)=BZ(I,J)/AII
4660  NEXT J
4670  FOR K=1 TO NZ
4680   AKI=AZ(K,I):IF K=I THEN 4730
4690   FOR J=1 TO NZ
4700    AZ(K,J)=AZ(K,J)-AKI*AZ(I,J)
4710    BZ(K,J)=BZ(K,J)-AKI*BZ(I,J)
4720   NEXT J
4730  NEXT K
4740 NEXT I
4750 RZ=0
4760 RETURN
4770 '
4780 ' *** 係数の誤差変換 ***
4790 '
4800 *PROPAGATION:
4810 FOR IS=1 TO M
4820  SD(IS)=SQR(ABS(BZ(IS,IS)*SN/(N1-M)))
4830  SE(IS)=SD(IS)/SQR(N1)
4840  '
4850  FOR JS=IS TO M
4860   COV(IS,JS)=BZ(IS,JS)*SN/(N1-M):COV(JS,IS)=COV(IS,JS)
4870  NEXT JS
4880 NEXT IS
4890 RETURN
4900 '
4910 ' *** SCATTER DIAGRAM ***
4920 '
4930 *SCATTER.DIAGRAM:
4940 CLS 3:WIDTH 80,25:COLOR 6
4950 'DMIN=XMIN(1):DMAX=XMAX(1)
4960 'PX=SQR(P(1)*P(1)*COS(P(3))*COS(P(3))+P(2)*P(2)*SIN(P(3))*SIN(P(3)))
4970 'DMIN=P(4)-PX:DMAX=P(4)+PX
4980 IF P(1)>P(2) THEN LARGE=P(1) ELSE LARGE=P(2)
4990 DMIN=P(4)-LARGE:DMAX=P(4)+LARGE
5000 GOSUB *LINER.SCALE:UO=SMIN:UL=SMAX:DU=DIF:SU=STP
5010 '
5020 'DMIN=XMIN(2):DMAX=XMAX(2)
5030 'PY=SQR(P(1)*P(1)*SIN(P(3))*SIN(P(3))+P(2)*P(2)*COS(P(3))*COS(P(3)))
5040 'DMIN=P(5)-PY:DMAX=P(5)+PY
5050 DMIN=P(5)-LARGE:DMAX=P(5)+LARGE
5060 GOSUB *LINER.SCALE:VO=SMIN:VL=SMAX:DV=DIF:SV=STP
5070 GOSUB *DRAW.AXIS
5080 GOSUB *DRAW.ELLIPSE:'GOSUB *GSAVE
5090 GOSUB *TEMP
5100 '
5110 CLS 3
5120 RETURN
5130 '
5140 ' *** 楕円 ***
5150 '
5160 *DRAW.ELLIPSE:
5170 'DRAW.COLOR=4
5180 WUO=UO:WUL=UL
5190 WVO=VO:WVL=VL
5200 WINDOW(WUO,-WVL)-(WUL,-WVO)
5210 VIEW(SX1,SY1)-(SX2,SY2)
5220 '
5230 GOSUB *CONTOUR
5240 '
5250 WINDOW(0,0)-(639,399)
5260 VIEW(0,0)-(639,399)
5270 RETURN
5280 '
5290 ' *** 輪郭 ***
5300 '
5310 *CONTOUR:
5320 C=COS(P(3)):S=SIN(P(3))
5330 AAA=P(1)
5340 BBB=P(2)
5350 X0=P(4):Y0=P(5)
5360 '
5370 G=0
5380 FOR ANGLE=0 TO 2*PI+.01 STEP PI/180
5390  GX=AAA*COS(ANGLE)*C-BBB*SIN(ANGLE)*S+X0
5400  GY=AAA*COS(ANGLE)*S+BBB*SIN(ANGLE)*C+Y0
5410  IF G=0 THEN PSET(GX,-GY),DRAW.COLOR:G=1
5420  LINE-(GX,-GY),DRAW.COLOR
5430 NEXT ANGLE
5440 RETURN
5450 '
5460 ' *** 座標軸 ***
5470 '
5480 *DRAW.AXIS:
5490 CLS 3
5500 SX1=59:SY1=360*(1-RY):SX2=580*RX+59:SY2=360
5510 LINE(SX1,SY1)-(SX2,SY2),GRP.COLOR,B
5520 RR=3:GOSUB *X.SCALE2:GOSUB *X.REF2
5530 RR=3:GOSUB *Y.SCALE2:GOSUB *Y.REF2
5540 RR=3:GOSUB *DOT.PLOT
5550 GOSUB *TITLE.BACK2
5560 RETURN
5570 '
5580 ' *** 等分目盛り (X) ***
5590 '
5600 *X.SCALE2:
5610 CU=(SX2-SX1)/DU
5620 IF KIND=0 THEN KARA=-RR:MADE=0
5630 IF KIND=1 THEN KARA=0 :MADE=RR
5640 IF KIND=2 THEN KARA=-RR:MADE=RR
5650 FOR K=0 TO DU
5660  LINE(CU*K+SX1,SY2+KARA)-(CU*K+SX1,SY2+MADE),GRP.COLOR
5670  LINE(CU*K+SX1,SY1-KARA)-(CU*K+SX1,SY1-MADE),GRP.COLOR
5680 NEXT K
5690 RETURN
5700 '
5710 ' *** 参照値の記入 (X) ***
5720 '
5730 *X.REF2:
5740 REF.COLOR=6
5750 UW=UL-UO
5760 FOR K=0 TO DU STEP SU
5770  F=UW*K/DU+UO:F$=STR$(F)
5780  IF F>=0 THEN F$=MID$(F$,2)
5790  FL=LEN(F$)
5800  FOR L=1 TO FL
5810   GX=CU*K+59-FL*8/2+(L-1)*8:GY=23*16
5820   PUT(GX,GY),KANJI(ASC(MID$(F$,L,1))),PSET,REF.COLOR,0
5830  NEXT L
5840 NEXT K
5850 RETURN
5860 '
5870 ' *** 等分目盛り (Y) ***
5880 '
5890 *Y.SCALE2:
5900 CV=(SY2-SY1)/DV
5910 IF KIND=0 THEN KARA=0 :MADE=RR
5920 IF KIND=1 THEN KARA=-RR:MADE=0
5930 IF KIND=2 THEN KARA=-RR:MADE=RR
5940 FOR K=0 TO DV
5950  LINE(SX1+KARA,SY2-CV*K)-(SX1+MADE,SY2-CV*K),GRP.COLOR
5960  LINE(SX2-KARA,SY2-CV*K)-(SX2-MADE,SY2-CV*K),GRP.COLOR
5970 NEXT K
5980 RETURN
5990 '
6000 ' *** 参照値の記入 (Y) ***
6010 '
6020 *Y.REF2:
6030 REF.COLOR=6
6040 VW=VL-VO
6050 FOR K=0 TO DV STEP SV
6060  F=VW*K/DV+VO:F$=STR$(F)
6070  IF F>=0 THEN F$=MID$(F$,2)
6080  FL=LEN(F$)
6090  FOR L=1 TO FL
6100   GX=48-FL*8+(L-1)*8:GY=360-CV*K-8
6110   PUT(GX,GY),KANJI(ASC(MID$(F$,L,1))),PSET,REF.COLOR,0
6120  NEXT L
6130 NEXT K
6140 RETURN
6150 '
6160 ' *** プロット ***
6170 '
6180 *DOT.PLOT:
6190 WUO=UO:WUL=UL
6200 WVO=VO:WVL=VL
6210 WX=WUL-WUO
6220 BX=(WUL*SX1-WUO*SX2)/WX
6230 AX=(SX2-SX1)/WX
6240 WY=WVL-WVO
6250 BY=(WVL*SY2-WVO*SY1)/WY
6260 AY=(SY1-SY2)/WY
6270 '
6280 FOR I=1 TO N1
6290 X=XX1(1,I):Y=XX1(2,I)
6300 XX=AX*X+BX
6310 YY=AY*Y+BY
6320 CIRCLE(XX,YY),RR,1
6330 PAINT(XX,YY),CLR,1
6340 CIRCLE(XX,YY),RR,CLR
6350 NEXT I
6360 RETURN
6370 '
6380 ' *** タイトル ***
6390 '
6400 *TITLE.BACK2:
6410 LX=INT((580*RX+59)/8)
6420 LY=INT(360*(1-RY)/16)
6430 LZ=INT((290*RX+59)/8)
6440 L1$="elliptic approximation by "
6450 L2$="GAUSS-NEWTON METHOD"
6460 L$=L1$+L2$
6470 LOCATE LZ-LEN(L$)\2,LY-3:PRINT L$
6480 '
6490 LOCATE LX+3,LY:PRINT "PARAMETERS: "
6500 FOR K=1 TO M
6510  V$="P"+MID$(STR$(K),2)+"="
6520  LOCATE LX+3,LY+K+1:PRINT V$;:PRINT P(K)
6530 NEXT K
6540 RETURN
6550 '
6560 *TEMP:
6570 LOCATE 0,24:PRINT "何かキーを押してください";:WHILE INKEY$="":WEND
6580 RETURN
6590 '
6600 ' *** 平均律スケールの作成 ***
6610 '
6620 *LINER.SCALE:
6630 DIM INTERVAL(10)
6640 RESTORE *REF.INTERVAL
6650 FOR I=1 TO 10:READ INTERVAL(I):NEXT I
6660 MAX.INTERVAL=10
6670 '
6680 ARGUMENT=DMAX-DMIN
6690 GOSUB *SCALE.RTN
6700 INDEX=CMP
6710 INTERVAL=INTERVAL(INDEX)*EP
6720 LO=INT(DMIN/INTERVAL)
6730 HI=-INT(-DMAX/INTERVAL)
6740 WHILE (HI-LO)>MAX.INTERVAL
6750  INDEX=INDEX+1
6760  IF INDEX>10 THEN INDEX=1:EP=EP*10
6770  INTERVAL=INTERVAL(INDEX)*EP
6780  LO=INT(DMIN/INTERVAL)
6790  HI=-INT(-DMAX/INTERVAL)
6800 WEND
6810 SMIN=LO*INTERVAL
6820 SMAX=HI*INTERVAL
6830 DIF=HI-LO
6840 STP=1
6850 ERASE INTERVAL
6860 RETURN
6870 '
6880 ' ** ラベリング関数 **
6890 '
6900 *SCALE.RTN:
6910 'RE=INT(LOG(ARGUMENT)/LOG(10))
6920 RE=INT(LOG(CDBL(ARGUMENT))/LOG(10#))
6930 'EP=10^RE
6940 EP=VAL("1E"+STR$(RE)):'[EXPONENT PART]
6950 MP=ARGUMENT/EP    :'[MANTISSA PART]
6960 FMP=INT(MP) :'[FLOORING MANTISSA PART]
6970 CMP=-INT(-MP):'[CEILING MANTISSA PART]
6980 RETURN
6990 '
7000 ' ** 参照間隔 **
7010 '
7020 *REF.INTERVAL:
7030 DATA .1,.2,.5,.5,.5,1,1,1,1,1
7040 '
7050 ' *** REPORT ***
7060 '
7070 *REPORT:
7080 CLS 3
7090 PRINT:PRINT
7100 PRINT "DATA No.=";N1
7110 PRINT
7120 PRINT " "," MEAN"," S.D."," MIN"," MAX"
7130 FOR I=1 TO NV
7140 PRINT "X("+MID$(STR$(I),2)+")",AVE(I),DEV(I),XMIN(I),XMAX(I)
7150 NEXT I
7160 PRINT:PRINT
7170 '
7180 PRINT "[ DEFINED EQUATION ]"
7190 PRINT "Y= ";FORM$
7200 '
7210 GOSUB *CEF.CONFIDENCE
7220 GOSUB *TEMP.STOP
7230 '
7240 CLS 3
7250 PRINT:PRINT "残差"
7260 PRINT " No."," OBSERVED Y"," EXPECTED Y"," RESIDUAL"
7270 FOR I=1 TO N1
7280  FOR V=1 TO NV:X(V)=XX1(V,I):NEXT V
7290  GOSUB *DEFINE.FORMULA:YH=FNY(X)
7300  PRINT I,Y1(I),YH,Y1(I)-YH
7310  IF (I MOD 20)=0 THEN PRINT
7320 NEXT I
7330 PRINT
7340 GOSUB *TEMP.STOP
7350 RETURN
7360 '
7370 *CEF.CONFIDENCE:
7380 PRINT
7390 PRINT "回帰係数とその95%信頼区間"
7400 DF1=1:DF2=N1-M
7410 GOSUB *CEF.CONFIDENCE.SUB
7420 PRINT:PRINT
7430 RETURN
7440 '
7450 *CEF.CONFIDENCE.SUB:
7460 FOR J=1 TO M
7470  P$="P("+MID$(STR$(J),2)+")= "
7480  PRINT P$;:PRINT P(J);
7490  IF SD(J)=0 THEN PRINT:GOTO 7520
7500  GOSUB *CEF.ERROR
7510  PRINT TAB(30);"S.E.=";SE(J)                             ;TAB(50);P(J)-SE(J)*UUT;" - ";P(J)+SE(J)*UUT
7520 NEXT J
7530 RETURN
7540 '
7550 *TEMP.STOP:
7560 PRINT "何かキーを押してください"
7570 WHILE INKEY$="":WEND
7580 RETURN
7590 '
7600 ' *** ERROR of COEFFICIENT ***
7610 '
7620 *CEF.ERROR:
7630 PP=.05 :GOSUB *F.PERCENT
7640 UUT=SQR(UUF)
7650 RETURN
7660 '
7670 ' ** NORMAL DISTRIBUTION **
7680 '
7690 *NORMAL.PERCENT:
7700 XXX=-LOG(4*PP*(1-PP))
7710 UUN=SQR(XXX*(2.06118-5.72622/(XXX+11.6406)))
7720 IF PP>.5 THEN UUN=-UUN
7730 RETURN
7740 '
7750 ' ** T-DISTRIBUTION **
7760 '
7770 *T.PERCENT:
7780 GOSUB *NORMAL.PERCENT
7790 UUN=ABS(UUN)
7800 UU2=UUN*UUN
7810 AA1=(UU2+1)/DF/4
7820 AA2=((5*UU2+16)*UU2+3)/96/DF/DF
7830 AA3=(((3*UU2+19)*UU2+17)*UU2-15)/384/DF/DF/DF
7840 UUT=UUN*(1+AA1+AA2+AA3)
7850 IF PP>.5 THEN UUT=-UUT
7860 RETURN
7870 '
7880 ' ** F-DISTRIBUTION **
7890 '
7900 *F.PERCENT:
7910 IF DF1=1 THEN DF=DF2:PP=PP/2:GOSUB *T.PERCENT                        :UUF=UUT^2:PP=PP*2:RETURN
7920 IF DF2=1 THEN DF=DF2:PP=(1-PP)/2:GOSUB *T.PERCENT                      :UUF=1/UUT^2:PP=1-PP*2:RETURN
7930 IF DF1=2 THEN UUF=DF2/2*(PP^(-2/DF2)-1):RETURN
7940 IF DF2=2 THEN UUF=2/DF1/((1-PP)^(-2/DF1)-1):RETURN
7950 AA=2/9/DF1:BB=2/9/DF2:CC=1-AA:DD=1-BB
7960 GOSUB *NORMAL.PERCENT
7970 UUF=CC*DD+UUN*SQR(CC*CC*BB+DD*DD*AA-AA*BB*UUN*UUN)
7980 UUF=(UUF/(DD*DD-BB*UUN*UUN))^3
7990 RETURN
8000 '
8010 ' ** CHI-SQUARE DISTRIBUTION **
8020 '
8030 *CHI2.PERCENT:
8040 IF DF=1 THEN PP=PP/2:GOSUB *NORMAL.PERCENT                         :UUX=UUN*UUN:PP=PP*2:RETURN
8050 IF DF=2 THEN UUX=-2*LOG(PP):RETURN
8060 GOSUB *NORMAL.PERCENT
8070 UUX=2/(9*DF)
8080 UUX=1-UUX+UUN*SQR(UUX)
8090 UUX=UUX^3*DF
8100 RETURN
8270 '
8280 ' ** 係数変換 **
8290 '
8300 *P2A:
8310 C=COS(P(3)):S=SIN(P(3))
8320 K=1-((P(4)*C+P(5)*S)/P(1))^2-((P(4)*S-P(5)*C)/P(2))^2
8330 A1=(C/P(1))^2+(S/P(2))^2
8340 A2=(1/P(1)^2-1/P(2)^2)*C*S*2
8350 A3=(S/P(1))^2+(C/P(2))^2
8360 A4=-(P(4)*C+P(5)*S)*C*2/P(1)^2-(P(4)*S-P(5)*C)*S*2/P(2)^2
8370 A5=-(P(4)*C+P(5)*S)*S*2/P(1)^2+(P(4)*S-P(5)*C)*C*2/P(2)^2
8380 A(1)=A1/K:A(2)=A2/K:A(3)=A3/K:A(4)=A(4)/K:A(5)=A5/K
8390 RETURN
8400 '
8410 *A2P:
8420 A1=A(1):A2=A(2):A3=A(3):A4=A(4):A5=A(5)
8430 DIF=A1-A3
8440 IF DIF=0 THEN P(3)=PI/4 ELSE P(3)=1/2*ATN(A2/(A1-A3))
8450 C=COS(P(3)):S=SIN(P(3))
8460 K=1/(1+(C*C-S*S)/4*((A4*C+A5*S)^2/(A1*C*C-A3*S*S)-(A4*S-A5*C)^2/(A1*S*S-A3*C*C)))
8470 P(1)=SQR((C*C-S*S)/(A1*C*C-A3*S*S)/K)
8480 P(2)=SQR(-(C*C-S*S)/(A1*S*S-A3*C*C)/K)
8490 P(4)=-(P(1)*P(1)*C*(A4*C+A5*S)+P(2)*P(2)*S*(A4*S-A5*C))/2*K
8500 P(5)=-(P(1)*P(1)*S*(A4*C+A5*S)-P(2)*P(2)*C*(A4*S-A5*C))/2*K
8510 RETURN
8520 '
8530 ' *** DEFINED EQUATION ***
8540 '
8550 *DEFINE.FORMULA3:
8560 ON L GOSUB *L1,*L2,*L3,*L4,*L5
8570 RETURN
8580 '
8590 *L1:DEF FNJ(X)=X(1)*X(1):RETURN
8600 *L2:DEF FNJ(X)=X(1)*X(2):RETURN
8610 *L3:DEF FNJ(X)=X(2)*X(2):RETURN
8620 *L4:DEF FNJ(X)=X(1)   :RETURN
8630 *L5:DEF FNJ(X)=X(2)   :RETURN
8640 '
8650 ' ** 初期値 **
8660 '
8670 *INIT.VAL:
8680 GOSUB *LEAST.SQUARES
8690 GOSUB *A2P
8700 RETURN
8710 '
8720 ' ** XT*X **
8730 '
8740 *LEAST.SQUARES:
8750 FOR M1=1 TO M
8760  FOR M2=M1 TO M
8770  S=0
8780   FOR I=1 TO N1
8790    FOR V=1 TO NV:X(V)=XX1(V,I):NEXT V
8800    L=M1:GOSUB *DEFINE.FORMULA3:L1=FNJ(X)
8810    L=M2:GOSUB *DEFINE.FORMULA3:L2=FNJ(X)
8820    S=S+WT(I)*L1*L2
8830   NEXT I
8840  AZ(M1,M2)=S:AZ(M2,M1)=S
8850  NEXT M2
8860 NEXT M1
8870 NZ=M
8880 '
8890 ' ** (XT*X)^(-1) **
8900 '
8910 GOSUB *INVERSE
8920 '
8930 ' ** XT*Y **
8940 '
8950 FOR J=1 TO M
8960  S=0
8970  FOR I=1 TO N1
8980   FOR V=1 TO NV:X(V)=XX1(V,I):NEXT V
8990   L=J:GOSUB *DEFINE.FORMULA3:L1=FNJ(X)
9000   S=S+WT(I)*L1*Z1(I)
9010  NEXT I
9020  W(J)=S
9030 NEXT J
9040 '
9050 ' ** (XT*X)^(-1)*XT*Y **
9060 '
9070 FOR J=1 TO M
9080  S=0
9090  FOR K=1 TO M
9100   S=S+BZ(J,K)*W(K)
9110  NEXT K
9120  A(J)=S
9130 NEXT J
9140 RETURN
9150 '
9160 *D:
9170 DATA 125
9180 DATA -165,-7.27991432
9190 DATA -164,-8.939199724
9200 DATA -163,-10.59978079
9210 DATA -162,-12.24757487
9220 DATA -161,-13.88258195
9230 DATA -160,-15.49711288
9240 DATA -159,-17.10654597
9250 DATA -158,-18.70319207
9260 DATA -157,-20.29344468
9270 DATA -156,-21.85682763
9280 DATA -155,-23.42789975
9290 DATA -154,-24.95421738
9300 DATA -153,-26.49332201
9310 DATA -152,-28.01195049
9320 DATA -151,-29.52548114
9330 DATA -150,-31.03901178
9340 DATA -149,-32.52057494
9350 DATA -148,-33.98805544
9360 DATA -147,-35.45043812
9370 DATA -146,-36.90003379
9380 DATA -145,-38.33684248
9390 DATA -144,-39.74678151
9400 DATA -143,-41.15801621
9410 DATA -142,-42.55007042
9420 DATA -141,-43.93573113
9430 DATA -140,-45.29452219
9440 DATA -139,-46.64821541
9450 DATA -138,-47.98912165
9460 DATA -137,-49.31724089
9470 DATA -136,-50.61849048
9480 DATA -135,-51.91464224
9490 DATA -134,-53.198007
9500 DATA -133,-54.46858477
9510 DATA -132,-55.71229289
9520 DATA -131,-56.95729667
9530 DATA -130,-58.17672647
9540 DATA -129,-59.38976277
9550 DATA -128,-60.57592942
9560 DATA -127,-61.75060474
9570 DATA -126,-62.91249307
9580 DATA -125,-64.0615944
9590 DATA -124,-65.18382608
9600 DATA -123,-66.30095993
9610 DATA -122,-67.39891329
9620 DATA -121,-68.47768616
9630 DATA -120,-69.53598288
9640 DATA -119,-70.58278826
9650 DATA -118,-71.61680666
9660 DATA -117,-72.63164456
9670 DATA -116,-73.61961281
9680 DATA -115,-74.59608974
9690 DATA -114,-75.55338617
9700 DATA -113,-76.49789561
9710 DATA -112,-77.4091419
9720 DATA -111,-78.31529036
9730 DATA -110,-79.19586483
9740 DATA -109,-80.05596315
9750 DATA -108,-80.89817664
9760 DATA -107,-81.72120965
9770 DATA -106,-82.52506216
9780 DATA -105,-83.30204502
9790 DATA -104,-84.06114305
9800 DATA -103,-84.8010606
9810 DATA -102,-85.51540416
9820 DATA -101,-86.20287807
9830 DATA -100,-86.87246715
9840 DATA -99,-87.52287574
9850 DATA -98,-88.14771035
9860 DATA -97,-88.7392818
9870 DATA -96,-89.31296844
9880 DATA -95,-89.86108108
9890 DATA -94,-90.39001324
9900 DATA -93,-90.87928875
9910 DATA -92,-91.34428593
9920 DATA -91,-91.79010263
9930 DATA -90,-92.19755835
9940 DATA -89,-92.57814442
9950 DATA -88,-92.92805866
9960 DATA -87,-93.25239893
9970 DATA -86,-93.5447717
9980 DATA -85,-93.79748784
9990 DATA -84,-94.01953215
10000 DATA -83,-94.20960898
10010 DATA -82,-94.36771833
10020 DATA -81,-94.47977753
10030 DATA -80,-94.56116492
10040 DATA -79,-94.60419133
10050 DATA -78,-94.60246326
10060 DATA -77,-94.55468505
10070 DATA -76,-94.46984152
10080 DATA -75,-94.34663701
10090 DATA -74,-94.16589104
10100 DATA -73,-93.93909492
10110 DATA -72,-93.66244649
10120 DATA -71,-93.33465009
10130 DATA -70,-92.95570571
10140 DATA -69,-92.50513721
10150 DATA -68,-92.0111099
10160 DATA -67,-91.44675412
10170 DATA -66,-90.81206988
10180 DATA -65,-90.10576151
10190 DATA -64,-89.33042034
10200 DATA -63,-88.47835721
10210 DATA -62,-87.54317862
10220 DATA -61,-86.50440843
10230 DATA -60,-85.38381844
10240 DATA -59,-84.154539
10250 DATA -58,-82.82296362
10260 DATA -57,-81.35582915
10270 DATA -56,-79.7685139
10280 DATA -55,-78.04054172
10290 DATA -54,-76.15912563
10300 DATA -53,-74.08460897
10310 DATA -52,-71.83237006
10320 DATA -51,-69.34996528
10330 DATA -50,-66.62460762
10340 DATA -49,-63.59106646
10350 DATA -48,-60.21996563
10360 DATA -47,-56.42689403
10370 DATA -46,-52.11594919
10380 DATA -45,-47.11960455
10390 DATA -44,-41.19749855
10400 DATA -43,-33.88800377
10410 DATA -42,-24.11061926
10420 DATA -41,-7.279912252
 
===================================
 
 データ読み込みサブルーチン(1980行〜2210行)では,プログラム中にDATA文で書き込まれたデータをREAD文により読み込んで計算を行っています.いわば,データをプログラム中に内蔵化する方法です.
 
 しかし,この計算例のように大量のデータを扱わなければならない場合には効率が悪く,外部メモリにデータを格納しておき(ファイル名を例えばdata01.txtとする),必要なときにそこからデータを呼び出して,データ処理とデータ入力を切り離した方が都合がよくなります.以下,データ読み込みサブルーチンの変更方法を示します.
 
1980 '
1990 ' *** データ読み込み ***
2000 '
2010 *READ.DATA:
2020 CLS 3
2030 'RESTORE *D
2040 'READ N1
2050 DFILE$="DATA01.TXT"
2060 OPEN DFILE$ FOR INPUT AS #1
2070 INPUT #1,N1
2080 '
2090 DIM XX1(NV,N1),YH(N1),WT(N1)
2100 DIM Y1(N1),E1(N1)
2110 DIM Z1(N1)
2120 DIM JACOBI(M,N1)
2130 FOR J=1 TO N1:WT(J)=1:NEXT J
2140 '
2150 FOR I=1 TO N1
2160  FOR J=1 TO NV
2170  'READ XX1(J,I)
2180   INPUT #1,XX1(J,I)
2190  NEXT J
2200 NEXT I
2210 CLOSE #1
 
===================================