bj.base.ibaraki.ac.jpbj.base.ibaraki.ac.jp/distribution/2_6m.pdf第2編 第6章 常微分方程式...
Post on 29-Jan-2020
2 Views
Preview:
TRANSCRIPT
第 2 編 第 6 章 常微分方程式
微分方程式とは未知関数とその導関数からなる等式のことであり,常微分方程式とは独
立変数が一つの微分方程式である.その例を次に示す.
𝑑𝑦(𝑥)
𝑑𝑥= 𝑓(𝑥, 𝑦)
常微分方程式が線形のときには解析的に解が得られるが,それが非線形のときには解析的
な解が得られることはほとんど期待できない.一方,数値的解法は,線形や非線形にかか
わらず,解を数値的に得られる.工学では非線形な問題を扱うことが多いので,数値的解
法が非常に役に立つ.
初めに数値的解法の中で最も簡単なEulerオイラー
法について説明する.次にそれよりも精度や効
率が良いRungeル ン ゲ
-Kuttaク ッ タ
法,Rungeル ン ゲ
-Kuttaク ッ タ
-Gillジ ル
法およびMilneミ ル ン
法について説明する.
6.0 Eulerオイラー
法
次の 1 階常微分方程式を数値的に解く方法について述べる.
𝑑𝑦
𝑑𝑥= 𝑓(𝑥, 𝑦) 教科書(1)式
図の曲線 y (x) について,任意の x のときの y の値は次のように求められる.
まず,x が x0から微小な量 h だけ増加した点 x1( x1 = x0 + h )における y1は,y の増分,
y1 - y0を f の 1 次近似(初期値 (x0, y0) 周りでテイラー展開)で示すと,
𝑦1 = 𝑦0 + ℎ ∙ 𝑓(𝑥0, 𝑦0) (P1)式
同様に
𝑦2 = 𝑦1 + ℎ ∙ 𝑓(𝑥1, 𝑦1)
…
𝑦𝑖+1 = 𝑦𝑖 + ℎ ∙ 𝑓(𝑥𝑖 , 𝑦𝑖) (P2)式
つまり初期値(𝑥0, 𝑦0)が与えられた後,(P2)式の計算を繰り返すことで,任意の xi のときの
yiの値が次々に求められる,これは関数 y (x)を得た(常微分方程式を解いた)ことになる.
オイラー法は AB 間が直線でよく近似できるような適切な h を選ぶと精密な解が得られる.
図 6.0 オイラー法
y(x)
𝑦1 B
A
𝑦0 h
x0 x1
6.1 Rungeル ン ゲ
-Kuttaク ッ タ
法
𝑑𝑦
𝑑𝑥= 𝑓(𝑥, 𝑦) 教科書(1)式
上において,x が x0から h だけ増加した点,x1 (x1 = x0 + h)における y1は Runge-Kutta の公
式でも計算できる.
𝑘1 = ℎ ∙ 𝑓(𝑥0, 𝑦0) 教科書(2)式
𝑘2 = ℎ ∙ 𝑓 (𝑥0 +ℎ
2, 𝑦0 +
𝑘1
2) 教科書(3)式
𝑘3 = ℎ ∙ 𝑓 (𝑥0 +ℎ
2, 𝑦0 +
𝑘2
2) 教科書(4)式
𝑘4 = ℎ ∙ 𝑓(𝑥0 + ℎ, 𝑦0 + 𝑘3) 教科書(5)式
𝑘 =1
6(𝑘1 + 2𝑘2 + 2𝑘3 + 𝑘4) 教科書(6)式
𝑦1 = 𝑦0 + 𝑘
同様に
𝑦2 = 𝑦1 + 𝑘𝑛𝑒𝑤
…
𝑦𝑖+1 = 𝑦𝑖 + 𝑘𝑛𝑒𝑤 (P3)式
𝑘𝑛𝑒𝑤は教科書(2)から(6)式によって毎回更新される.つまり初期値(𝑥0, 𝑦0)が与えられた後,
(P3)式の計算を繰り返すことで,任意の xiのときの yiの値が求められる.式の意味は次のと
おり.(下の図も参照のこと.)
① 傾き f (x0, y0) で 点 (x0, y0) から x が h だけ進むと,k1を得る.
② この線上の点 (x0 + h/2, y0+k1/2) での傾きで (x0, y0) から h だけ進むと,k2を得る.
③ 同様に,傾き f (x0+h/2, y0+k2/2) で (x0, y0) から h だけ進むと,k3を得る.
④ 次に,傾き f (x0+h, y0+k3) で (x0, y0) から h だけ進むと,k4を得る.
⑤ 次に,①から④の加重平均 k を教科書(6) 式で求め,y1を得る.
つまり①から⑤は x0における傾きを 4 次の式で求めていることに相当する.
図 6.1 Rungeル ン ゲ
-Kuttaク ッ タ
法
ここでルンゲ・クッタ法のプログラムを示す.下の常微分方程式について,初期条件(x0, y0)
= (0, 0)のもとで x = π / 2 まで,15 等分して求める.
𝑑𝑦
𝑑𝑥= sin 𝑥 + cos𝑦
コンパイルするときは次のように行う.
gcc -o sp6_1 sp6_1.c -lm
例題 6.1 のプログラム(演習問題 1,2,4,7,8,10 に関係する.)
#include<stdio.h>
#include<math.h>
#define F(x, y) (sin(x)+cos(y)) /* 式を必ず括弧でくくること */
#define h 3.1416/(2.*15.) /* 刻み値 h の定義(rad 単位),π/2 を 15 等分 */
void main(void)
{
double x, y, k1, k2, k3, k4;
int i=0; /* i: 計算のステップ数 */
x = y = 0.; /* 初期値の設定,x0, y0 */
printf("i x y¥n"); /* 変数名の画面表示 */
printf("%2d %6.3f %6.3f¥n", i, x, y); /* 初期値の画面表示 */
do {
i++; /*ステップを 1 つ進める */
k1=h*F(x, y); /* 教科書(2)式の計算 */
k2=h*F(x+h/2., y+k1/2.); /* 教科書(3)式の計算 */
k3=h*F(x+h/2., y+k2/2.); /* 教科書(4)式の計算 */
k4=h*F(x+h, y+k3); /* 教科書(5)式の計算 */
y+=(k1+2.*k2+2.*k3+k4)/6.; /* 教科書(6)式の計算 */
x+=h; /* x の増分の計算:xi+1=xi+h */
printf("%2d %6.3f %6.3f¥n", i, x, y); /* 値の表示 */
} while(i-15<0); /* 計算を 15 回繰り返す */
}
define文の注意: define 文で宣言した式はコンパイル時に次のように解釈される.
define 文は式の計算の優先順序を考慮して括弧をつける必要がある.例をあげる.
#define F1(x, y) (x+y) /* 式を括弧でくくる場合 */
#define F2(x, y) x+y /* 式を括弧でくくらない場合 */
int a, b;
a = 2 * F1(1, 1); /* 左の式は次のように計算される:a = 2 * (1 + 1) = 4 */
b = 2 * F2(1, 1); /* 左の式は次のように計算される:a = 2 * 1 + 1 = 3 */
define 文での式の表現の煩わしさを避けるなら,副関数を使えばよい.
(例) double F2(double x, double y) { return( x + y ); }
演習問題を解くときに注意が必要である.
6.2 Rungeル ン ゲ
-Kuttaク ッ タ
-Gillジ ル
法
𝑑𝑦
𝑑𝑥= 𝑓(𝑥, 𝑦) 教科書(1)式
上において,x が x0から h だけ増加した点 x1 (x1 = x0 + h)における y1は次の Runge-Kutta-Gill
の公式でも計算できる.
𝑘1 = ℎ ∙ 𝑓(𝑥0, 𝑦0),𝑟1 =1
2(𝑘1 − 2𝑞0)
𝑦(1) = 𝑦0+ 𝑟1,𝑞1 = 𝑞0 + 3𝑟1 −
1
2𝑘1
𝑘2 = ℎ ∙ 𝑓 (𝑥0 +ℎ
2, 𝑦(1)),𝑟2 = (1 −
√2
2) (𝑘2 − 𝑞1)
𝑦(2) = 𝑦(1) + 𝑟2,𝑞2 = 𝑞1 + 3𝑟2 − (1 −√2
2) 𝑘2
𝑘3 = ℎ ∙ 𝑓 (𝑥0 +ℎ
2, 𝑦(2)),𝑟3 = (1 +
√2
2) (𝑘3 − 𝑞2)
𝑦(3) = 𝑦(2) + 𝑟3,𝑞3 = 𝑞2 + 3𝑟3 − (1 +√2
2) 𝑘3
𝑘4 = ℎ ∙ 𝑓(𝑥0 + ℎ, 𝑦(3)),𝑟4 =
1
6(𝑘4 − 2𝑞3)
𝑦1= 𝑦(3) + 𝑟4,𝑞4 = 𝑞3 + 3𝑟4 −
1
2𝑘4 }
教科書(7)式
ただし q0の初期値は 0 である.
次に,得られた x1を x0,y1を y0,また q4を q0と置き直した後,再び教科書(7)式を計算す
る.これらを繰り返すことによって,任意の xiのときの yiの値を求めることができる.
ここでルンゲ・クッタ・ジル法のプログラムを示す.問題は例題 6.1 と同じである.下の
常微分方程式について,初期条件(x0, y0) = (0, 0)のもとで x = π / 2 まで,15 等分して求める.
𝑑𝑦
𝑑𝑥= sin 𝑥 + cos𝑦
コンパイルするときは次のように行う.
gcc -o sp6_2 sp6_2.c -lm
例題 6.2 のプログラム(演習問題 5,8,9 に関係する.)
#include<stdio.h>
#include<math.h>
#define F(x, y) (sin(x)+cos(y)) /* 関数の定義 */
#define h 3.1416/(2.*15.) /* 刻み値 h の定義(rad 単位),π/2 を 15 等分 */
#define s sqrt(2.)/2. /* ルンゲ・クッタ・ジル法で使う定数√2/2 の定義 */
void main(void)
{
double k1, k2, k3, k4, r1, r2, r3, r4, q0=0., q1, q2, q3, q4; /* q0 の初期値は 0 */
double x=0., y=0., y1, y2, y3; /* 初期値設定 x0=0,y0=0 */
int i=0; /* 計算のステップ数 */
printf("i x y¥n"); /* 変数名の画面表示 */
printf("%2d %6.3f %6.3f¥n", i, x, y); /* 初期値の画面表示 */
do {
i++; /* ステップ数を増やす */
k1=h*F(x, y); r1=(k1-2.*q0)/2.; /* 教科書(7)式の計算 */
y1=y+r1; q1=q0+3.*r1-k1/2.;
k2=h*F(x+h/2., y1); r2=(1.-s)*(k2-q1);
y2=y1+r2; q2=q1+3.*r2-(1.-s)*k2;
k3=h*F(x+h/2., y2); r3=(1.+s)*(k3-q2);
y3=y2+r3; q3=q2+3.*r3-(1.+s)*k3;
k4=h*F(x+h, y3); r4=(k4-2.*q3)/6.;
y=y3+r4; q4=q3+3.*r4-k4/2.;
x+=h; q0=q4; /* x1を x0,また q4を q0と置き直おす */
printf("%2d %6.3f %6.3f¥n", i, x, y); /* 計算値の表示 */
} while(i-15<0); /* 計算を 15 回繰り返す */
}
6.3 Milneミ ル ン
法
図で四つの座標データ,A(xi-3,yi-3) ,B(xi-2,
yi-2) ,C(xi-1,yi-1) ,D(xi ,yi)および f が与えら
れたとき,座標 E(xi+1,yi+1) が求められる.𝑥𝑖+1に
ついては 𝑥𝑖+1 = 𝑥𝑖 + ℎ からすぐ求められる.一
方,𝑦𝑖+1は予測子と修正子による二つの値から
求められる.前者はLagrangeラ グ ラ ン ジ ュ
の補間多項式で近
似した 𝑦𝑖+1 の値,後者はSimpsonシ ン プ ソ ン
の 1/3 公式で
近似したその値である.
ここで教科書(1)式をもう一度示す.
𝑑𝑦
𝑑𝑥= 𝑓(𝑥, 𝑦) 教科書(1)式
ここで yi+1を予測したもの,予測子(predictor),
𝑦𝑖+1(𝑃)を使う.教科書(1)式を点 A から E まで積分すると,
𝑦𝑖+1(𝑃)− 𝑦𝑖−3 = ∫ 𝑓(𝑥, 𝑦)
𝑥𝑖+1
𝑥𝑖−3
𝑑𝑥 ≈ ∫ 𝑃(𝑥)𝑥𝑖+1
𝑥𝑖−3
𝑑𝑥
教科書(8)式
左辺は 𝑦𝑖+1(𝑃)
と 𝑦𝑖−3 の差を意味し,中央は区間 h ごとの高さの差の累積を意味する.右辺
は f を補間多項式 P (x)で近似している.今,f を 3 次のLagrangeラ グ ラ ン ジ ュ
の補間多項式で近似するな
ら P (x)は教科書 p. 148,(2)式より,
𝑃(𝑥) = 𝑓𝑖−3(𝑥+ℎ)𝑥(𝑥−ℎ)
(−ℎ)(−2ℎ)(−3ℎ)+ 𝑓𝑖−2
(𝑥+2ℎ)𝑥(𝑥−ℎ)
ℎ∙(−ℎ)∙(−2ℎ)+ 𝑓𝑖−1
(𝑥+2ℎ)(𝑥+ℎ)(𝑥−ℎ)
2ℎ∙ℎ∙(−ℎ)+ 𝑓𝑖
(𝑥+2ℎ)(𝑥+ℎ)𝑥
3ℎ∙2ℎ∙ℎ
教科書(9)式
教科書(9)式を教科書(8)式へ代入し,P (x)を 𝑥𝑖−1を中心として𝑥𝑖−3から 𝑥𝑖+1まで,つまり-2h
から 2h まで積分すると,予測子𝑦𝑖+1(𝑃)は
𝑦𝑖+1(𝑃)
= 𝑦𝑖−3 +4
3ℎ(2𝑓𝑖−2 − 𝑓𝑖−1 + 2𝑓𝑖) 教科書(10)式
A
B
C
D
E
yi+1 f
yi
yi-1
yi-2
yi-3
h h h h h
xi-3 xi-2 xi-1 xi xi+1
図 6.2 Milne法
ただし𝑓𝑖 = 𝑓(𝑥𝑖 , 𝑦𝑖)である.(付録,計算 1 参照.)
次に予測子を修正するもの,修正子(corrector)について考える.今,
𝑓𝑖+1 = 𝑓 (𝑥𝑖+1, 𝑦𝑖+1(𝑃) ) 教科書(11)式
として,xi-1,xi,xi+1の 3 つの点に Simpson の 1/3 公式(教科書 P.158,教科書(11)式)を適
用すると,修正子 𝑦𝑖+1(𝐶)は
𝑦𝑖+1(𝐶)
= 𝑦𝑖−1 +ℎ
3(𝑓𝑖−1 + 4𝑓𝑖 + 𝑓𝑖+1) 教科書(12)式
予測子と修正子を求め,それらの差が非常に小さくなったとき, 𝑦𝑖+1 を予測子の値とす
る.その判定式は次のとおり.
|𝑦𝑖+1(𝑃)− 𝑦𝑖+1
(𝐶)| < 𝜀 教科書(13)式
ε はゼロに近い値で,教科書の例題 6.3 では ε = 1×10-5を採用している.
もし上が成立しなければ,修正子 𝑦𝑖+1(𝐶)
を予測子 𝑦𝑖+1(𝑃)
に置き換え,教科書 (11) 式の 𝑓𝑖+1
を計算し,𝑦𝑖+1(𝐶)
を計算する.これらの手順を繰り返す.(教科書の 𝑓𝑖+1(𝐶)
は 𝑦𝑖+1(𝐶)
の間違い
である.例題 6.3 のプログラムを見よ.)
ミルン法の長所は,過去に計算した値から新しい y を求めるため,計算量はルンゲ・クッ
タ法より少ないことである.一方その短所は,計算を始めるために四つの点のデータを他
のアルゴリズムで求める手間があり,またオイラー法やルンゲクッタ法より計算の安定性
が劣ることである.
ここでミルン法のプログラムを示す.問題は例題 6.1 と同じである.下の常微分方程式に
ついて,初期条件(x0, y0) = (0, 0)のもとで x = π/2 まで,x を 15 等分して求める.初期値から
3 点はルンゲ・クッタ法で求めている.
𝑑𝑦
𝑑𝑥= sin 𝑥 + cos𝑦
コンパイルするときは次のように行う.
gcc -o sp6_3 sp6_3.c -lm
例題 6.3 のプログラム(演習問題 3,6,8 に関係する.)
#include<stdio.h>
#include<math.h>
#define F(x, y) (sin(x)+cos(y)) /* 関数の定義 */
#define h 3.1416/(2.*15.) /* 刻み値 h の定義 */
#define eps 1.e-5 /* 収束判定条件で使われる閾値(しきいち) */
void main(void)
{
double x[16], y[16], k1, k2, k3, k4;
double f, f1, f2, fp, yp, yc;
int i=0; /*ステップ数 */
x[0]=y[0]=0.; /* 初期値設定 x0=0,y0=0 */
printf("i x y¥n"); /* 変数名の画面表示 */
printf("%2d %6.3f %6.3f¥n", i, x[0], y[0]); /* 初期値の画面表示 */
for(i=0; i<3; ++i) { /* x1 から x3 までの計算 */
k1=h*F(x[i], y[i]); /* ルンゲ・クッタ法による計算 */
k2=h*F(x[i]+h/2., y[i]+k1/2.);
k3=h*F(x[i]+h/2., y[i]+k2/2.);
k4=h*F(x[i]+h, y[i]+k3);
y[i+1]=y[i]+(k1+2.*k2+2.*k3+k4)/6.;
x[i+1]=x[i]+h;
printf("%2d %6.3f %6.3f¥n", i+1, x[i+1], y[i+1]); /* 計算結果の表示 */
}
for(i=3; i<15; ++i){ /* ミルン法による計算 */
x[i+1]=x[i]+h; /* xi+1=xi+h */
f=F(x[i], y[i]); /* fi の計算 */
f1=F(x[i-1], y[i-1]); /* fi-1 の計算 */
f2=F(x[i-2], y[i-2]); /* fi-2 の計算 */
yp=y[i-3]+4./3.*h*(2.*f2-f1+2*f); /* 教科書(10)式の計算 */
while(1) {
fp=F(x[i+1], yp); /* 教科書(11)式の計算 */
yc=y[i-1]+h/3.*(f1+4*f+fp); /* 教科書(12)式の計算 */
if(fabs(yp-yc)<eps) break; /* 教科書(13)式の収束判定 */
yp=yc; /* */
}
y[i+1]=yc;
printf("%2d %6.3f %6.3f¥n", i+1, x[i+1], y[i+1]);
}
}
6.4 連立常微分方程式(n 階常微分方程式の解き方)
ここでは n 階常微分方程式の解き方について学ぶ.手順は,
(手順 1)n 階常微分方程式を n 元連立 1 階常微分方程式へ変換する.
(手順 2)n 個の 1 階常微分方程式をオイラー法やルンゲ・クッタ法などで解く
これらの処理により,n 階常微分方程式の数値解が得られる.
例として次の 2 階常微分方程式(例題 6.4)について説明する.
𝑑2𝑦
𝑑𝑥2= 𝑥
𝑑𝑦
𝑑𝑥+ 𝑦 (P3)式
手順 1: 𝑑𝑦1
𝑑𝑥= 𝑦2とおくと,上の式は次の 2 元連立 1 階常微分方程式へ変換できる.
{
𝑑𝑦1
𝑑𝑥= 𝑦2
𝑑𝑦2
𝑑𝑥= 𝑥𝑦2 + 𝑦1
(P4)式
上の二つの式をベクトル表示で 1 つにまとめると次式のように表現できる.
𝑑𝒚
𝑑𝑥= 𝒇(𝑥, 𝒚) (P5)式
ただし𝒚 = [𝑦1𝑦2],𝒇 = [
𝑓1(𝑥, 𝑦1, 𝑦2)
𝑓2(𝑥, 𝑦1, 𝑦2)] = [
𝑦2𝑥𝑦2 + 𝑦1
]である.
手順 2: 上の二つの式をオイラー法で解くならば,式は次のようになる.
𝑦1 𝑖+1 = 𝑦1 𝑖 + ℎ ∙ 𝑦2 𝑖 (P6a)式
𝑦2 𝑖+1 = 𝑦2 𝑖 + ℎ ∙ (𝑥𝑖 ∙ 𝑦2 𝑖 + 𝑦1 𝑖+1) (P6b)式
初期条件,つまり i = 0 のときの x0,y10,y20を用意して,(P6a)式,次に(P6b)式を計算すれ
ば数値解が得られる.
n 階常微分方程式について扱うならば,yと fを次のように拡張すればよい.
𝒚 = [
𝑦1𝑦2⋮𝑦𝑛
], 𝒇 =
[ 𝑓1(𝑥, 𝑦1, 𝑦2,⋯,𝑦𝑛)
𝑓2(𝑥, 𝑦1, 𝑦2,⋯,𝑦𝑛)
⋮𝑓𝑛(𝑥, 𝑦1, 𝑦2,⋯,𝑦𝑛)]
これをルンゲ・クッタ法で解くならば,教科書(2)式は次式に書き換えられる.
𝒌1 = ℎ𝒇(𝑥0, 𝒚0)
ただし
[
𝑘11𝑘12⋮𝑘1𝑛
] =
[ ℎ𝑓1(𝑥0, 𝑦10, 𝑦20,⋯,𝑦𝑛0)
ℎ𝑓2(𝑥0, 𝑦10, 𝑦20,⋯,𝑦𝑛0)
⋮ℎ𝑓𝑛(𝑥0, 𝑦10, 𝑦20,⋯,𝑦𝑛0)]
である.同様にして,教科書(3),(4),(5) 式からベクトル k2,k3,k4が求められる.従って
教科書 (6) 式も同様に次のように書き換えられる.
𝒌 = [
𝑘1𝑘2⋮𝑘𝑛
] =1
6{[
𝑘11𝑘12⋮𝑘1𝑛
] + 2 [
𝑘21𝑘22⋮𝑘2𝑛
] + 2 [
𝑘31𝑘32⋮𝑘3𝑛
] + [
𝑘41𝑘42⋮𝑘4𝑛
]}
これらより,
𝒚1 = 𝒚0 + 𝒌
同様に
𝒚2 = 𝒚1 + 𝒌𝑛𝑒𝑤
…
𝒚𝑖+1 = 𝒚𝑖 + 𝒌𝑛𝑒𝑤
以上の手順で n 階常微分方程式の解を得ることができる.
ここで 2 階常微分方程式の解法についてのプログラムを示す.下の 2 階常微分方程式に
ついて,初期条件(x0, y0) = (0, 1) ,𝑑𝑦
𝑑𝑥=1 のもとで,ルンゲ・クッタ法により x = 1 まで,10
等分して求める.
𝑑2𝑦
𝑑𝑥2= 𝑥
𝑑𝑦
𝑑𝑥+ 𝑦
上の式を次のように 1 階連立常微分方程式に変換して求めればよい.
𝑑𝑦1
𝑑𝑥= 𝑦2,
𝑑𝑦2
𝑑𝑥= 𝑥𝑦2 + 𝑦1
コンパイルするときは次のように行う.
gcc -0 sp6_4 sp6_4.c -lm
例題 6.4 のプログラム(演習問題 7,9,10 に関係する.)
#include<stdio.h>
/* RNGKUT:ルンゲ・クッタ法の計算をする副関数,FUN:方程式の右辺を計算する副関数 */
void RNGKUT(int, double, double *, double *, double *, double *, double *, double *, double);
double FUN(int, double, double *, int);
void main(void)
{
double y[2], k1[2], k2[2], k3[2], k4[2], ywork[2]; /* y, k1, k2, k3, k4, 作業領域 ywork */
/* double x, h;
int i, n;
scanf("%d %lf", &n, &h); /* キーボードからのデータ入力 */
scanf("%lf %lf %lf", &x, &y[0], &y[1]);
*/
int i;
double n=2, h=0.1; /* n: 階数, h: 刻み値 */
double x=0.0; /* x の初期値: x0 */
y[0]=1.0, y[1]=1.0; /* y[0]: y1 の初期値: y0, y[1]: y2=dy1/dx の初期値 */
printf("i x y1 y2¥n"); /* 変数名の画面表示 */
printf("0 %6.3f %6.3f %6.3f¥n", x, y[0], y[1]); /* 初期値の画面表示 */
for(i=1; i<=10; i++){ /* 10 回の計算を繰り返す */
RNGKUT(n, x, y, k1, k2, k3, k4, ywork, h); /* 変数名の画面表示 */
x+=h; /* xi+1=xi+h */
printf("%2d %6.3f %6.3f %6.3f¥n", i, x, y[0], y[1]); /*結果の表示 */
}
}
/* ルンゲ・クッタ法の計算をする副関数*/
void RNGKUT(int n, double x, double *py, double *pk1, double *pk2, double *pk3, double *pk4,
double *pywork, double h)
{
int i;
for(i=0; i<n; i++){ /* k1 の計算 */
*(pk1+i)=h*FUN(i, x, py, n);
}
for(i=0; i<n; i++){ /* y の変化量 y+k1/2 を配列 ywork に記憶する */
*(pywork+i)=*(py+i)+*(pk1+i)/2;
}
for(i=0; i<n; i++){ /* k2 の計算 */
*(pk2+i)=h*FUN(i, x+h/2, pywork, n);
}
for(i=0; i<n; i++){ /* y の変化量 y+k2/2 を配列 ywork に記憶する */
*(pywork+i)=*(py+i)+*(pk2+i)/2;
}
for(i=0; i<n; i++){ /* k3 の計算 */
*(pk3+i)=h*FUN(i, x+h/2, pywork, n);
}
for(i=0; i<n; i++){ /* y の変化量 y+k3 を配列 ywork に記憶する */
*(pywork+i)=*(py+i)+*(pk3+i);
}
for(i=0; i<n; i++){ /* k4 の計算*/
*(pk4+i)=h*FUN(i, x+h, pywork, n);
}
for(i=0; i<n; i++){ /* y1 の計算 */
*(py+i)+=(*(pk1+i)+2**(pk2+i)+2**(pk3+i)+*(pk4+i))/6;
}
return;
}
double FUN(int i, double x, double *py, int n) /* 方程式の右辺を計算する副関数 */
{
double f;
if((i+1)==1){ /* i=1 のとき,dy1/dx=y2 の計算 */
f=*(py+1);
return f;
} else { /* i=2 のとき,dy2/dx=xy2+y1 の計算*/
f=x**(py+1)+*(py+0);
return f;
}
}
6.5 演習問題について
1. define を使わず,副関数で計算するとよい.次のように define 文をコメントにする.
/* #define F(x, y) ((x*x)+y) */
次に main 文の前に副関数を挿入する.
double F(double x, double y) { return(x*x+y); }
お勧めしませんが,もし define 文を使うなら,次のように記述する.
#define F(x, y) (pow(x, 2)+y)
4.初期条件より 15 = C・exp( - 02/2)より C = 15.つまり y = 15exp( -12 / 2 ) = 0.9097959896.項目
1 も参照のこと.
5.,6.項目 4 を参照のこと.
7.一般解は y = sin(x)である.
付録
(計算 1)
教科書(9)式の計算
Lagrange の補間多項式は,次数 n = 3,教科書 P.148,(2)式より,次のようになる.
𝑃3(𝑥) = 𝑎0𝑥3 + 𝑎1𝑥
2 + 𝑎2𝑥1 + 𝑎3 (C1)式
=∑𝑓𝑖
3
𝑖=0
(𝑥 − 𝑥0)(𝑥 − 𝑥1)… (𝑥 − 𝑥𝑖−1)(𝑥 − 𝑥𝑖+1)… (𝑥 − 𝑥3)
(𝑥𝑖 − 𝑥0)(𝑥𝑖 − 𝑥1)… (𝑥𝑖 − 𝑥𝑖−1)(𝑥𝑖 − 𝑥𝑖+1)… (𝑥𝑖 − 𝑥3)
= 𝑓0(𝑥 − 𝑥1)(𝑥 − 𝑥2)(𝑥 − 𝑥3)
(𝑥0 − 𝑥1)(𝑥0 − 𝑥2)(𝑥0 − 𝑥3)+ 𝑓1
(𝑥 − 𝑥0)(𝑥 − 𝑥2)(𝑥 − 𝑥3)
(𝑥1 − 𝑥0)(𝑥1 − 𝑥2)(𝑥1 − 𝑥3)
+ 𝑓2(𝑥 − 𝑥0)(𝑥 − 𝑥1)(𝑥 − 𝑥3)
(𝑥2 − 𝑥0)(𝑥2 − 𝑥1)(𝑥2 − 𝑥3)+ 𝑓3
(𝑥 − 𝑥0)(𝑥 − 𝑥1)(𝑥 − 𝑥2)
(𝑥3 − 𝑥0)(𝑥3 − 𝑥1)(𝑥3 − 𝑥2)
(C2)式
(C2)式の右辺の各項は教科書(9)式について次のように対応している.
第 1 項:𝑝1 ≡ 𝑓𝑖−3(𝑥+ℎ)𝑥(𝑥−ℎ)
(−ℎ)(−2ℎ)(−3ℎ)
第 2 項:𝑝2 ≡ 𝑓𝑖−2(𝑥+2ℎ)𝑥(𝑥−ℎ)
ℎ(−ℎ)(−2ℎ)
第 3 項:𝑝3 ≡ 𝑓𝑖−1(𝑥+2ℎ)(𝑥+ℎ)(𝑥−ℎ)
2ℎ∙ℎ(−ℎ)
第 4 項:𝑝4 ≡ 𝑓𝑖(𝑥+2ℎ)(𝑥+ℎ)𝑥
3ℎ∙2ℎ∙ℎ
(変換のルール)
R1: xの添え字が小さいものから大きいものを引くとき hは負となり,その逆は正となる.
上の式において黄色でマークされているところは,教科書と記述が異なるが,分母の符号
は変わらないので,結果(計算値)は同じである.
変換の具体的な例を示す.
|←h→|←h→|←h→|←h→|
xi-3 xi-2 xi-1 xi xi+1 :教科書(9)式の記号
x0 x1 x2 x3 x4 :(C2)式の記号
↑
原点
原点は x2なので,例えば(C2)式の記号と教科書(9)式の対応は次のようになる.
(𝑥 − 𝑥1) → (𝑥2 − 𝑥1) ∶ 𝑥 + ℎ
(𝑥 − 𝑥2) → (𝑥2 − 𝑥2) ∶ 𝑥
(𝑥 − 𝑥3) → (𝑥2 − 𝑥3) ∶ 𝑥 − ℎ
となっている.
教科書(10)式の計算
まず (10)式は次のように展開できる.
𝑦𝑖+1(𝑃)
= 𝑦𝑖−3 +4
3ℎ(2𝑓𝑖−2 − 𝑓𝑖−1 + 2𝑓𝑖) = 𝑦𝑖−3 +
8ℎ ∙ 𝑓𝑖−23
−4ℎ ∙ 𝑓𝑖−1
3+8ℎ ∙ 𝑓𝑖3
(イ) (ロ) (ハ)
次に p1から p4の積分を求めると
𝑝1 ≡ 𝑓𝑖−3(𝑥 + ℎ)𝑥(𝑥 − ℎ)
(−ℎ)(−2ℎ)(−3ℎ)= 𝑓𝑖−3
𝑥3 − ℎ2𝑥
−6ℎ3
∫ 𝑝1
2ℎ
−2ℎ
𝑑𝑥 =𝑓𝑖−3−6ℎ3
{∫ 𝑥32ℎ
−2ℎ
𝑑𝑥 − ℎ2∫ 𝑥2ℎ
−2ℎ
𝑑𝑥} = 0
同様に積分の計算結果を示すと
∫ 𝑝2
2ℎ
−2ℎ
𝑑𝑥 =8ℎ ∙ 𝑓𝑖−2
3
∫ 𝑝3
2ℎ
−2ℎ
𝑑𝑥 = −4ℎ ∙ 𝑓𝑖−1
3
∫ 𝑝4
2ℎ
−2ℎ
𝑑𝑥 =8ℎ ∙ 𝑓𝑖3
上の積分の総和は(10)式の(イ)(ロ)および(ハ)に等しい.
top related