数値解析 - 奈良女子大学kako/teaching/na/chap3.pdf3. 方程式の求解 5 従って、...
Transcript of 数値解析 - 奈良女子大学kako/teaching/na/chap3.pdf3. 方程式の求解 5 従って、...
1
数値解析
加古富志雄
令和元年 5月 8日
目 次3 方程式の求解 1
3.1 二分法 (Bisection Method) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
3.2 挟み撃ち法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
3.3 割線法 (Secant Method) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3.3.1 割線法の収束 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.4 Newton法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.4.1 Newton法の例: cの平方根 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.4.2 Newton法の例: cの逆数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.4.3 Newton法の収束 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.4.4 重解の場合の収束 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.5 プログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.5.1 2分法のプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.5.2 割線法のプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.5.3 Newton法のプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.6 ベアストウ・ヒッチコックの方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.6.1 2次因子による分解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.6.2 ベアストウ・ヒッチコック法のプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.7 DKA法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.7.1 n次方程式の全ての解を求める . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.7.2 DKA法のプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.7.3 実行結果 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.8 課題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3 方程式の求解3.1 二分法 (Bisection Method)
f(x) = 0 の解を求める方法として二分法がある。いま、x = a, x = b で f(x) の符号が異なる、すなわちf(a)f(b) < 0が成り立っているとすると、少なくとも区間 (a, b)の中に f(x) = 0の解が一つ存在する。x0 = a, x1 = bとして、f(x0) > 0とする。x2 = (x0 + x1)/2について、f(x2)の値を求めたときその符号は
0,+,−のいずれかである。f(x2) = 0の時、x = x2が解になる。f(x2) > 0の時、解は、区間 (x0, x2)にある。x1
の値を x2 に改めて、同じ計算を繰返すことにより、真の値の近似値を求めることが出来る。
3. 方程式の求解 2
x0x1 x2=(x0+x1)/2
x3=(x0+x2)/2
図 1: 二分法による救解
繰返す毎に区間幅は 1/2倍になるので、xn は真の解 x̄に
|xn − x̄| ∝ |x0 − x̄|2n
で近づいて行く。
3.2 挟み撃ち法x0 = a, x1 = bとして、f(x0) > 0とする。x2 として、2点 (x0, f(x0))と (x1, f(x1))を通る直線と x軸との交点を x2 とする。この直線が x軸と交わる点を x2 とすると、
−f(x0) =f(x0)− f(x1)
x0 − x1(x2 − x0)
従って、x2 = x0 −
x0 − x1
f(x0)− f(x1)f(x0) =
−x0f(x1) + x1f(x0)
f(x0)− f(x1)
二分法による方法と同じく、f(x2)の符号により、f(x2) = 0の時、x = x2 が解になる。f(x2) > 0)の時、解は、区間 (x0, x2)にある。x1 の値を x2 に改めて、同じ計算を繰返す。
3. 方程式の求解 3
x0x1 x2
x3
図 2: 挟み撃ち法による救解
3.3 割線法 (Secant Method)
挟み撃ち法と同じ計算で x2 を求める。挟み撃ち法では、f(x0)と f(x1)が異符号であるという条件をつけていたが、割線法では、同符号であっても構わない。f(x) = 0の近似値 x = x0 および x = x1 に対して、2つの点 (x0, f(x0))と (x1, f(x1))を結ぶ直線
y − f(x0) =f(x0)− f(x1)
x0 − x1(x− x0)
を考える。この直線が x軸と交わる点を x2 とすると、
−f(x0) =f(x0)− f(x1)
x0 − x1(x2 − x0)
従って、x2 = x0 −
x0 − x1
f(x0)− f(x1)f(x0) =
−x0f(x1) + x1f(x0)
f(x0)− f(x1)
以後、xi−2 と xi−1 から xi を計算すると、xi は f(x) = 0の解に近づく。x0 と x1 が十分解に近いとき、割線法による繰返しで、xn は真の解 x̄に
|xn − x̄| ∝ |x0 − x̄|αn
で近づく。ここで、αは黄金分割比、α = 1+√5
2 ≈ 1.618、である。
3. 方程式の求解 4
x0x1 x2
x3
図 3: 割線法による救解
3.3.1 割線法の収束
f(x) = 0の解を x = x̄とし、xn − x̄ = ϵn と置く。今、|ϵn|は |x̄|と比べて十分小さいと仮定する。
f(xn) = f(x̄+ ϵn) = ϵnf′(x̄) +
1
2ϵ2nf
′′(x̄) + · · ·
f(xn+1) = f(x̄+ ϵn+1) = ϵn+1f′(x̄) +
1
2ϵ2n+1f
′′(x̄) + · · ·
と、xn+2 − xn = − xn+1 − xn
f(xn+1)− f(xn)f(xn)
から、
ϵn+2 − ϵn = − ϵn+1 − ϵn
f ′(x̄)(ϵn+1 − ϵn) +12f
′′(x̄)(ϵ2n+1 − ϵ2n) + · · ·(ϵnf
′(x̄) +1
2ϵ2nf
′′(x̄) + · · ·)
= − 1
f ′(x̄)
{1− f ′′(x̄)
2f ′(x̄)(ϵn+1 + ϵn) + · · ·
}(ϵnf
′(x̄) +1
2ϵ2nf
′′(x̄) + · · ·)
≈ −ϵn +f ′′(x̄)
2f ′(x̄)ϵn+1ϵn
3. 方程式の求解 5
従って、ϵn+2 ≈ f ′′(x̄)
2f ′(x̄)ϵn+1ϵn
つまり、ϵn+2 ∝ ϵn+1ϵn
ϵn が c−Tn で零に近づくとすると、Tn はフィボナッチの方程式
Tn+2 = Tn + Tn+1
を満たす。すなわち、十分大きい nに対して、
Tn ≈ αn, α =1 +
√5
2
3.4 Newton法f(x) = 0の近似値を x = x0 としたとき、x = x0 における f(x)の接線の方程式は、
y − f(x0) = f ′(x0)(x− x0)
で与えられる。接線が x軸と交わる点は
−f(x0) = f ′(x0)(x− x0)
を解いて、x = x0 −
f(x0)
f ′(x0)
この値を x1 として、x = x1 における f(x)の接線を求め、その接線が x軸に交わる点を x2 とする、これを繰返すことで、
xn+1 = xn − f(xn)
f ′(xn)
xn は f(x)の解に近づく。x0 十分解に近いとき、Newton法による繰返しは、xn は真の解 x̄に
|xn − x̄| ∝ |x0 − x̄|2n
で近づく。
3.4.1 Newton法の例: cの平方根
f(x) = x2 − c
から、f(x) = 0の解 x > 0で√cが得られる。ニュートン法の繰返しは
xn+1 = xn − f(xn)
f ′(xn)= xn − x2
n − c
2xn=
1
2(xn +
c
xn)
で与えられる。k乗根の場合には、
f(x) = xk − c
としてxn+1 = xn − f(xn)
f ′(xn)= xn − xk
n − c
kxk−1n
=1
k((k − 1)xn +
c
xk−1n
)
3. 方程式の求解 6
x0x1
図 4: ニュートン法による救解
3.4.2 Newton法の例: cの逆数
f(x) =1
x− c
を元にニュートン法を構成すると
xn+1 = xn − f(xn)
f ′(xn)= xn −
1xn
− c
− 1x2n
= 2xn − cx2n = xn(2− cxn)
が得られる。最初頃のコンピュータでは割り算の計算が手間がかかっていたので、割り算を掛け算のみを使って計算する方法として使われたことがある。
3.4.3 Newton法の収束
f(x) = 0の解を x = x̄とし、xn − x̄ = ϵn と置くと、
f(xn) = f(x̄+ ϵn) = f(x̄) + ϵnf′(x̄) +
1
2ϵ2nf
′′(x̄) + · · ·
f ′(xn) = f ′(x̄) + ϵnf′′(x̄) + · · ·
ただし、|ϵn|は |x̄|と比べて十分小さいとする。
3. 方程式の求解 7
xn − x̄− f(xn)
f ′(xn)= ϵn − (ϵnf
′(x̄) +1
2ϵ2nf
′′(x̄) + · · ·) 1
f ′(x̄)
{1− ϵn
f ′′(x̄)
f ′(x̄)+ · · ·
}=
1
2ϵ2n
f ′′(x̄)
f ′(x̄)+ · · ·
から、ϵn+1 ≈ 1
2ϵ2n
f ′′(x̄)
f ′(x̄)
すなわち、ϵn+1 ∝ ϵ2n
となる。つまり、Newton法で近似した解の誤差は二乗で小さくなる(有効桁が二倍になる)。これを二乗収束(quadratic convergence)という。
f(x) = (x2 + 1)(x− 1)を初期値 x0 = 1.5で出発してニュートン法を繰り返した結果を次に示す。
n= 0, x = 1.50000000000000000, f= 1.62500000000000000
n= 1, x = 1.15789473684210531, f= 0.36958740341157614
n= 2, x = 1.02133275871357010, f= 0.04358539886831365
n= 3, x = 1.00044548394324240, f= 0.00089136488678110
n= 4, x = 1.00000019836755438, f= 0.00000039673518746
n= 5, x = 1.00000000000003930, f= 0.00000000000007860
n= 6, x = 1.00000000000000000, f= 0.00000000000000000
xが解 1の近くでは、1に急速に収束している。なお、同じ方程式で初期値 x0 = 0.5で計算を行うと、次のような結果になる。
n= 0, x = 0.50000000000000000, f= -0.62500000000000000
n= 1, x = 1.33333333333333348, f= 0.92592592592592649
n= 2, x = 1.08080808080808088, f= 0.17520372586182217
n= 3, x = 1.00602488608759844, f= 0.01212258937879453
n= 4, x = 1.00003608121621212, f= 0.00007216503617955
n= 5, x = 1.00000000130180711, f= 0.00000000260361422
n= 6, x = 1.00000000000000000, f= 0.00000000000000000
n= 7, x = 1.00000000000000000, f= 0.00000000000000000
この方程式では f ′(x)は正である。この場合、x0 < 1から出発すると一度 x1 > 1に移り、その後で x = 1に単調に減少していく。x0 > 1から出発すると、そのまま単調に x = 1に減少していく。f ′(x)が解の近傍で負の時は逆になる。
3.4.4 重解の場合の収束
ただし、f(x) = 0の解、x = x̄が重解の時、f ′(x̄)が零になるため、収束が悪くなる。このとき、
f(xn) =1
2ϵ2nf
′′(x̄) +1
6ϵ3nf
′′′(x̄) + · · ·
f ′(xn) = ϵnf′′(x̄) +
1
2ϵ2nf
′′′(x̄) + · · ·
3. 方程式の求解 8
より、
xn − x̄− f(xn)
f ′(xn)= ϵn − (
1
2ϵ2nf
′′(x̄) +1
6ϵ3nf
′′′(x̄) + · · ·) 1
ϵnf ′′(x̄)
{1 + ϵn
f ′′′(x̄)
2f ′′(x̄)+ · · ·
}=
1
2ϵn − 5
12ϵ2n
f ′′′(x̄)
f ′′(x̄)+ · · ·
すなわち、ϵn+1 ≈ 12ϵn つまり、Newton法の繰返し一回について、誤差は半分になるだけである。一般にm重の
重解の場合、(f(x)のm回微分までが全て x = x̄で零の場合)
ϵn+1 ∝ m− 1
mϵn
となる。割線法で同じく重解の場合、
ϵn+2 − ϵn = − ϵn+1 − ϵn12f
′′(x̄)(ϵ2n+1 − ϵ2n) + · · ·
{1
2ϵ2nf
′′(x̄) + · · ·}
= − ϵ2nϵn+1 + ϵn
+ · · ·
すなわち、ϵn+2 ≈ ϵn+1ϵn
ϵn+1 + ϵn
となる。ϵn+1 = kϵn ならば、ϵn+2 =
k
k + 1ϵn
である。k2 = kk+1 を満たす、kを求めると、
k =
√5− 1
2≈ 0.6180339
f(x) = x(x− 1)2 に対してニュートン法を適用した結果である。
n= 0, x = 1.50000000000000000, f= 0.37500000000000000
n= 1, x = 1.28571428571428581, f= 0.10495626822157442
n= 2, x = 1.15714285714285725, f= 0.02857434402332366
n= 3, x = 1.08356729975227095, f= 0.00756708528986283
n= 4, x = 1.04333505337168320, f= 0.00195930691103099
n= 5, x = 1.02210835351713092, f= 0.00049958540068942
n= 6, x = 1.01117244936353212, f= 0.00012621821040792
n= 7, x = 1.00561691623817140, f= 0.00003172696031863
n= 8, x = 1.00281627965670972, f= 0.00000795376823287
n= 9, x = 1.00141011434494476, f= 0.00000199122636886
n=10, x = 1.00070555322884447, f= 0.00000049815658691
n=11, x = 1.00035290093419049, f= 0.00000012458301931
n=12, x = 1.00017648158538996, f= 0.00000003115124663
n=13, x = 1.00008824857707168, f= 0.00000000778849862
n=14, x = 1.00004412623523109, f= 0.00000000194721055
n=15, x = 1.00002206360436441, f= 0.00000000048681338
n=16, x = 1.00001103192387886, f= 0.00000000012170469
n=17, x = 1.00000551599236487, f= 0.00000000003042634
n=18, x = 1.00000275800378891, f= 0.00000000000760661
n=19, x = 1.00000137900379604, f= 0.00000000000190165
3. 方程式の求解 9
n=20, x = 1.00000068950237342, f= 0.00000000000047541
n=21, x = 1.00000034475130550, f= 0.00000000000011885
n=22, x = 1.00000017237568239, f= 0.00000000000002971
n=23, x = 1.00000008618784864, f= 0.00000000000000743
n=24, x = 1.00000004309392621, f= 0.00000000000000186
n=25, x = 1.00000002154696355, f= 0.00000000000000046
n=26, x = 1.00000001077348188, f= 0.00000000000000012
n=27, x = 1.00000000538674105, f= 0.00000000000000003
n=28, x = 1.00000000269337064, f= 0.00000000000000001
n=29, x = 1.00000000134668543, f= 0.00000000000000000
n=30, x = 1.00000000067334271, f= 0.00000000000000000
n=31, x = 1.00000000033667136, f= 0.00000000000000000
n=32, x = 1.00000000016833579, f= 0.00000000000000000
n=33, x = 1.00000000008416801, f= 0.00000000000000000
1の近傍では、一回の繰り返しで誤差 |xn − 1|が 1/2倍に減少していく様子が見て取れる。
3.5 プログラム3.5.1 2分法のプログラム
1 // bisection2 #include "pch.h"
3 #include <iostream>4 #include <stdlib.h>5
6 #define USE MATH DEFINES7 #Include <math.h>8
9 double f(double x);10
11 int main(int ac, char ∗av[])12 {13 double x0, x1, x2;14 double f0, f1, f2;15 int n;16
17 x0 = 1; x1 = 2;18 f0 = f(x0);19 f1 = f(x1);20 if(f0 ∗ f1 > 0) {21 printf("f(x0)とf(x1)が同符号です。\n");22 exit(1);23 }24
25 printf("n=%2d, x = %25.17f, f=%25.17f\n", 0, x0, f0);26 printf("n=%2d, x = %25.17f, f=%25.17f\n", 1, x1, f1);27 n=2;28 while(fabs(x0 − x1) > 1.0e−10) {29 x2 = (x0+x1)/2;30 f2 = f(x2);31 printf("n=%2d, x = %25.17f, f=%25.17f\n", n, x2, f2);32 if(f2 == 0) {
3. 方程式の求解 10
33 printf("解は$%25.17fです\n", x2);34 }35 if(f0∗f2 < 0) {36 x1 = x2;37 f1 = f2;38 } else {39 x0 = x2;40 f0 = f2;41 }42 n++;43 }44 }45
46 double f(double x)47 {48 double r;49 r = x∗x∗x−3;50 return r;51 }
3.5.2 割線法のプログラム
1 // secant method2 #include "pch.h"
3 #include <iostream>4 #define USE MATH DEFINES5 #include <math.h>6
7 double f(double x);8
9 int main(int ac, char ∗av[])10 {11 double x0, x1, x2;12 double f0, f1, f2;13 int n;14
15 //x0 = 1.4; x1 = 1.5;16 x0 = 1.0; x1 = 2.0;17 f0 = f(x0);18 f1 = f(x1);19
20 printf("n=%2d, x = %25.17f, f=%25.17f\n", 0, x0, f0);21 printf("n=%2d, x = %25.17f, f=%25.17f\n", 1, x1, f1);22 n=2;23 while(fabs(x0 − x1) > 1.0e−10) {24 x2 = (−x0∗f1+x1∗f0)/(f0−f1);25 f2 = f(x2);26 printf("n=%2d, x = %25.17f, f=%25.17f\n", n, x2, f2);27 if(f2 == 0) {28 break;29 }30
31 x0 = x1;32 x1 = x2;33 f0 = f1;34 f1 = f2;35 n++;
3. 方程式の求解 11
36 }37 printf("解は$%25.17fです\n", x2);38 }39
40 double f(double x)41 {42 double r;43 r = x∗x∗x−3;44 return r;45 }
3.5.3 Newton法のプログラム
1 // newton method2 #include "pch.h"
3 #include <iostream>4 #incluce <math.h>5
6 double f(double x);7 double df(double x);8
9 int main(int ac, char ∗av[])10 {11 double x0;12 double f0;13 double fp, dx;14 int n;15
16 x0 = 1;17 f0 = f(x0);18 printf("n=%2d, x = %25.17f, f=%25.17f\n", 0, x0, f0);19 n=1;20 do {21 fp = df(x0);22 dx = f0/fp;23
24 x0 = x0−dx;25 n++;26 f0 = f(x0);27 printf("n=%2d, x = %25.17f, f=%25.17f\n", n, x0, f0);28 } while(fabs(dx) > 1.0e−10) ;29 printf("解は$%25.17fです\n", x0);30 }31
32 double f(double x)33 {34 double r;35 r = x∗x∗x−3;36 return r;37 }38
39 double df(double x)40 {41 double r;42 r = 3∗x∗x;43 return r;44 }
3. 方程式の求解 12
3.6 ベアストウ・ヒッチコックの方法n次の代数方程式
f(x) = anxn + an−1x
n−1 + · · ·+ a0, an ̸= 0, n ≥ 2
の解を求める方法について述べる。
3.6.1 2次因子による分解
f(x)にたいして、それの 2次の因子の x2 − ux− vを求めることが出来れば、f(x) = 0の解の内の二つの解が二次方程式 x2 − ux− v = 0の解として求められる。f(x)を x2 − ux− vで割ったとき、
f(x) = (x2 − ux− v)(bnxn + · · ·+ b2) + b1(x− u) + b0
となるとすると、右辺を展開して
f(x) = bnxn + (bn−1 − ubn)x
n−1 + (bn−2 − ubn−1 − vbn)xn−2 + · · ·
+(bn−k − ubn−k+1 − vbn−k+2)xn−k−2 + · · ·
+(b2 − ub3 − vb4)x2 + (−ub2 − vb3 + b1)x+ (−vb2 − ub1 + b0)
より、xのべき乗の項を比較することにより、
bn = an
bn−1 = an−1 + ubn
bk = ak + ubk+1 + vbk+2, k = n− 2, . . . , 2
b1 = a1 + ub2 + vb3
b0 = a0 + ub1 + vb2
と求められる。いま、u, v を変化したとき、この式によって、b1, b0 が決まると考えると、b1, b0 は u, v の関数になっている。つまり、b0(u, v), b1(u, v)である。f(x)が x2 − ux− vで割切れたとき、b0と b1は共にゼロになる。つまり、
b0(u, v) = 0
b1(u, v) = 0
を満たす、u, vを求めれば、それが求める二次方程式である。この方程式の解を求めるためにニュートン法を使う。
b0(uk +∆u, vk +∆v) = b0(u, v) +∂
∂ub0(u, v)∆u+
∂
∂vb0(u, v)∆v = 0
b1(uk +∆u, vk +∆v) = b1(u, v) +∂
∂ub1(u, v)∆u+
∂
∂vb1(u, v)∆v = 0
から∆u,∆vを求めると、∆ =
∂
∂ub0(u, v)
∂
∂vb1(u, v)−
∂
∂vb0(u, v)
∂
∂ub1(u, v)
と置くと、
∆u = − 1
∆(b0(u, v)
∂
∂vb1(u, v)− b1(u, v)
∂
∂vb0(u, v))
∆v =1
∆(b0(u, v)
∂
∂ub1(u, v)− b1(u, v)
∂
∂ub0(u, v))
3. 方程式の求解 13
となる。これから
uk+1 = uk +∆u
vk+1 = vk +∆v
の繰返しにより、(uk, vk), k = 1, . . . ,を求めることにより、解の近似値が求められる。∂bk/∂uおよび ∂bk/∂vを求めておく。上の式から ck = ∂bk/∂uと置くと、
cn = 0
cn−1 = bn
ck = bk+1 + uck+1 + vck+2, k = n− 2, · · · , 0
を満たすことから、cn = 0, cn−1 = anを初期値とする漸化式の解として、c0, c1が求まる。また、∂bk/∂vを dk と置くと、同じく
dn = 0
dn−1 = udn = 0
dn−2 = bn + udn−1 + vdn = bn
dk = bk + udk+1 + vdk+2, k = n− 3, . . . , 0
を満たす。ckの満たす漸化式と比較することにより、dk = ck+1となることが分かる。従って、ckを使うと、ニュートン法の繰返しは
uk+1 = uk − b0c2 − b1c1c0c2 − c21
vk+1 = vk +b0c1 − b1c0c0c2 − c21
3.6.2 ベアストウ・ヒッチコック法のプログラム
1 #include "pch.h"
2 #include <iostream>3 #include <math.h>4
5 #define EPS 1.0e−56 #define N 47
8 void bairstow(double ∗, double ∗, double[], int);9 void root(double, double, double);
10
11 int12 main(int ac, char ∗ av[])13 {14 int n = N;15 double a[] = { 62, −50, 2, −2, 1 };16 double p, q;17
18 printf(" real part \t imag part\n");19 while (n > 0) {20 if (n == 1) {21 printf("%8.5lf\t\t%8.5lf\n", −a[0] / a[1], 0.0);
3. 方程式の求解 14
22 break;23 }24 if (n == 2) {25 root(a[2], a[1], a[0]);26 break;27 }28
29 bairstow(&p, &q, a, n);30 root(1.0, −p, −q);31 n −= 2;32 }33 return 0;34 }35
36 void37 bairstow(double ∗p, double ∗q, double a[], int n)38 {39 double b[N + 1], c[N];40 int k;41 double u, v, du, dv;42
43 double d, e;44
45 u = 1.0;46 v = 1.0;47
48 do {49 b[n] = a[n];50 b[n − 1] = a[n − 1] + u ∗ b[n];51 c[n] = 0;52 c[n − 1] = a[n];53 for (k = n − 2; k >= 0; k−−) {54 b[k] = a[k] + u ∗ b[k + 1] + v ∗ b[k + 2];55 c[k] = b[k + 1] + u ∗ c[k + 1] + v ∗ c[k + 2];56 }57 d = 1 / (c[0] ∗ c[2] − c[1] ∗ c[1]);58 du = (b[0] ∗ c[2] − b[1] ∗ c[1]) ∗ d;59 dv = (b[0] ∗ c[1] − b[1] ∗ c[0]) ∗ d;60 u = u − du;61 v = v + dv;62 } while ((fabs(du) > EPS) && (fabs(dv) > EPS));63 ∗p = u;64 ∗q = v;65
66 for (k = 0; k <= n − 2; k++)67 a[k] = b[k + 2];68 }69
70 void71 root(double a, double b, double c)72 {73 double d, f;74 d = b ∗ b − 4 ∗ a ∗ c;75 a = 1 / (2 ∗ a);76 if (d <= 0) {77 b = b ∗ a;78 f = sqrt(−d) ∗ a;79 printf("%8.5lf\t%8.5lf\n", −b, f);80 printf("%8.5lf\t%8.5lf\n", −b, −f);81 } else {82 b = b ∗ a;
3. 方程式の求解 15
83 f = sqrt(d) ∗ a;84 printf("%8.5lf\t%8.5lf\n", −b + f, 0.0);85 printf("%8.5lf\t%8.5lf\n", −b − f, 0.0);86 }87 }
3.7 DKA法3.7.1 n次方程式の全ての解を求める
方程式f(x) = anx
n + an−1xn−1 + · · ·+ a0 = 0
の解は重複解を含めれば n個ある。ここでは、n個の解を一度に求めるDKA法(デュラン・ケルナー・アバース法)について述べる。n個の解をそれぞれ xi, i = 1, . . . , nと置くと、
f(x) = an(x− x1) · (x− x2) · · · (x− xn)
と表される。この式を展開して f(x)の xk の係数を比較することにより、解と係数の関係式よりx1 + x2 + · · ·+ xn = −an−1/an
x1x2 + x1x3 + · · ·+ xn−1xn = an−2/an...
x1x2 · · ·xn = (−1)na0/an
が得られる。この式を x1, . . . , xn に関する連立方程式と見て、ニュートン法により解を求めることを考える。簡単のため、n = 3の場合を考える。方程式は
f1 = x1 + x2 + x3 + a2/a3
f2 = x1x2 + x1x3 + x3x1 − a1/a3
f3 = x1x2x3 + a0/a3
これから∆x1,∆x2,∆x3 に対する方程式は∆x1 +∆x2 +∆x3 = −f1
(x2 + x3)∆x1 + (x1 + x3)∆x2 + (x1 + x2)∆x3 = −f2
x2x3∆x1 + x1x3∆x2 + x1x2∆x3 = −f3
(1)
となる。これを解くと
∆x1 = − f1x21 − f2x1 + f3
x21 − x1x2 − x1x3 + x2x3
∆x2 = − −f1x22 + f2x2 − f3
x1x2 − x1x3 − x22 + x2x3
∆x3 = − f1x23 − f2x3 + f3
x1x2 − x1x3 − x2x3 + x23
ここで、x21 − x1x2 − x1x3 + x2x3 = (x1 − x2)(x1 − x3)
3. 方程式の求解 16
および
f1x21 − f2x1 + f3 = (x1 + x2 + x3)x
21 − (x1x2 + x2x3 + x3x1)x1 + x1x2x3 + (a2x
21 + a1x1 + a0)/a3
= x31 + (a2x
21 + a1x1 + a0)/a3 = f(x1)/a3
より、
∆x1 = − f(x1)
a3(x1 − x2)(x1 − x3)
∆x2 = − f(x2)
a3(x2 − x1)(x2 − x3)
∆x3 = − f(x3)
a3(x3 − x1)(x3 − x2)
となる。一般に n次の方程式の場合
∆xi = − f(xi)
an(xi − x1) · · · (xi − xi−1)(xi − xi+1) · · · (xi − xn), i = 1, . . . , n
つまり、ニュートン法での繰返しは
x(k+1)i = x
(k)i − f(x
(k)i )
an(x(k)i − x
(k)1 ) · · · (x(k)
i − x(k)i−1)(x
(k)i − x
(k)i+1) · · · (x
(k)i − x
(k)n )
, i = 1, . . . , n
で与えられる。この繰返しが通常のニュートン法
x(k+1) = x(k) − f(x(k))
f ′(x(k))
との違いは、分母にある。通常のニュートン法での分母の式は
f ′(x(k)) =
n∑l=1
an(x(k) − x1) · · · (x(k) − xl−1)(x
(k) − xl+1) · · · (x(k) − xn)
≈ an(x(k) − x1) · · · (x(k) − xi−1)(x
(k) − xi+1) · · · (x(k) − xn)
である。ただし、xl, l = 1, . . . , nは f(x) = 0の解で、k → ∞で x(k) は解 xi に収束するとした。ニュートン法で計算するときの初期値をどのように選べば良いかについては、アバースが提案した
x(0)k = −an−1
nan+ r exp i
(2(k − 1)π
n+
3
2n
)= −an−1
nan+ r cos
(2(k − 1)π
n+
3
2n
)+ ir sin
(2(k − 1)π
n+
3
2n
)が良いとされている。ここで、rは全ての解が
|xi +an−1
n| ≤ r
を満たすように取る。例えば、伊理は
|an|xn − |an−2|xn−2 − · · · − |a1|x− |a0| = 0
の正の実数解を rとする方法を提案している。
3. 方程式の求解 17
3.7.2 DKA法のプログラム
1 #include "pch.h"
2 #include <iostream>3 #include <stdlib.h>4 #include <complex.h>5
6 #define USE MATH DEFINES7 #include <math.h>8
9 #define EPS 1.0e−510 #define N 1011
12 double center(double a[], int n);13 double radius aberth(double a[], int n);14 double radius iri(double a[], int n);15 double newton(double a[], int n, double x0);16 double delta(double a[], int n, double x);17 void init(complex double xi[], double a[], int n);18 void dka(complex double xi[], double a[], int n, int miter);19 complex double eval(double a[], int n, complex double x);20
21 int22 main(int ac, char ∗ av[])23 {24 complex double x[N];25 double a[N + 1] = { 62, −50, 2, −2, 1 };26 int i, n;27
28 n = 4;29 dka(x, a, n, 1000);30 for (i = 0; i < n; i++) {31 printf(" x%02d = %10.5lf + i %10.5lf\n", i, creal(x[i]),32 cimag(x[i]));33 }34 return 0;35 }36
37 double38 center(double a[], int n)39 {40 double r;41 r = −a[n − 1] / (n ∗ a[n]);42 return r;43 }44
45 double46 radius aberth(double a[], int n)47 // Aberth’s initial value48 {49 int i, m;50 double r, t, g;51 r = 0;52 m = 0;53 for (i = 0; i <= n; i++) {54 if (a[i] != 0)55 m++;56 }57 for (i = 0; i < n; i++) {
3. 方程式の求解 18
58 t = m ∗ a[i] / a[n];59 t = fabs(t);60 t = pow(t, 1.0 / (n − i));61 if (r < t)62 r = t;63 }64 return r;65 }66
67 double68 radius iri(double a[], int n)69 // Iri’s initial value70 {71 int i;72 double qn;73 double r, p;74
75 double q[N + 1];76 for (i = 0; i < n; i++)77 q[i] = −fabs(a[i]);78 q[n] = fabs(a[n]);79 p = radius aberth(a, n);80 r = newton(q, n, p);81 return r;82 }83
84 double85 newton(double a[], int n, double x0)86 {87 int i;88 double x, y;89
90 if (n < 1)91 return 0.0;92 i = 0;93 x = x0;94 do {95 y = delta(a, n, x0);96 x0 = x0 − y;97 i++;98 if (i > 100) {99 printf("newton iteration exceed max\n");
100 return x0;101 }102 } while (fabs(y) > EPS);103 return x;104 }105
106 double107 delta(double a[], int n, double x)108 {109 int i;110 double c, d;111 c = 0;112 d = 0;113 for (i = n; i >= 0; i−−) {114 c = c ∗ x + a[i];115 d = d ∗ x + i ∗ a[i];116 }117 c = c ∗ x + a[0];118 return c / d;
3. 方程式の求解 19
119 }120
121 void122 init(complex double xi[], double a[], int n)123 {124 int i;125 double r, c, t;126 complex double ci;127
128 r = radius iri(a, n);129 c = center(a, n);130 for (i = 0; i < n; i++) {131 t = 2 ∗ M PI ∗ i / n + 3.0 / (2 ∗ n);132 ci = t ∗ I; // imaginary t133 ci = c + r ∗ cexp(ci);134 xi[i] = ci;135 }136 }137
138
139 void140 dka(complex double xi[], double a[], int n, int miter)141 {142 int i, j, m, flag;143 double mval, amod, absx, absn;144 complex double t, low, up, mod;145 complex double ans[N];146
147 init(xi, a, n);148 for (m = 0; m < miter; m++) {149 mval = 0;150 flag = 0;151 for (i = 0; i < n; i++) {152 low = 1;153 for (j = 0; j < i; j++) {154 t = xi[i] − xi[j];155 low = low ∗ t;156 }157 for (j = i + 1; j < n; j++) {158 t = xi[i] − xi[j];159 low = low ∗ t;160 }161 low = low ∗ a[n];162 up = eval(a, n, xi[i]);163 mod = up / low;164 t = xi[i] − mod;165 ans[i] = t;166 // check convergence167 amod = cabs(mod);168 absx = cabs(xi[i]);169 absn = cabs(ans[i]);170 if (amod > (absx + absn) ∗ EPS + EPS)171 flag = 1;172 if (mval < amod)173 mval = amod;174 }175 printf("%d-th iteration , modval = %lf\n", m, mval);176 for (i = 0; i < n; i++) {177 xi[i] = ans[i];178 }179 if (flag == 0)
3. 方程式の求解 20
180 return;181 }182 }183
184 complex double185 eval(double a[], int n, complex double x)186 {187 int i;188 complex double c;189 c = 0;190 for (i = n; i >= 0; i−−) {191 c = c ∗ x + a[i];192 }193 return c;194 }
3.7.3 実行結果
62, -50, 2, -2, 1
f(x) = x4 − 2x3 + 2x2 − 50x+ 62
の方程式について、DKA法で計算した結果は次のようになった。
0-th iteration , modval = 2.602562
1-th iteration , modval = 2.015877
2-th iteration , modval = 1.643693
3-th iteration , modval = 1.512457
4-th iteration , modval = 1.782065
5-th iteration , modval = 0.927769
6-th iteration , modval = 0.234715
7-th iteration , modval = 0.007851
8-th iteration , modval = 0.000013
x00 = 3.80357 + i -0.00000
x01 = -1.53927 + i 3.22733
x02 = -1.53927 + i -3.22733
x03 = 1.27497 + i 0.00000
正確な値は
x1 ≒ 3.8035652182992258987393187426883364283550681815015
x2,3 ≒ −1.5392671107619448678126107618491304072835385814393
±3.2273317776133725023560034859776136652398641604583i
x4 ≒ 1.2749690032246638368859027810099243862120089813771
である。
3.8 課題問題 3.1 f(x) = x3 + 3x2 について、f(x) = 0の解を、二分法、割線法およびニュートン法によって求めよ。初期値としては、例えば、x0 = −4, x1 = 1を使え。
3. 方程式の求解 21
問題 3.2 f(x) = x3 − 4x2 + x + 6 の解をニュートン法によって求めるプログラムを作成せよ。初期値 x0 を −2
から 4の間で動かしたとき、ニュートン法によって求められる解はどのようになるか調べよ。f(x) = 0の解は 3
つある。どの解に収束するか調べてみよ。まず、−2から 4までの間で x0 を 0.1刻みで変更してニュートン法を行なったときどの解が得られるかを調べよ。得られる解が変化する箇所をもっと細かく刻んで計算することで、もっと詳しく調べよ。
問題 3.3 DKA法によって、f(x) = x3 − 4x2 + x+ 6 = 0 のすべての解を求めよ。