常微分方程式の初期値問題の数値解法のうち、
比較的簡単で、高精度な解が得られるため、良く用いられる方法として
8、
次の Runge-Kutta法
(4次のRunge-Kutta法, 古典的Runge-Kutta法とも呼ばれる) がある。
これは次の漸化式で
を定めるものである。
![]() |
Euler法にせよ、Runge-Kutta 法にせよ、
多くの場合
は等分点に取る。つまり
を
等分するとして
(
以下この節では、特に断りのない限り、
解こうとしている区間
を
等分する場合を考えることにする。
C プログラマー向けの説明
「常微分方程式の初期値問題を解くプログラムの書き方 §2 Euler法, Runge-Kutta法入門 -- 1次元の問題」 の §2.3.2 Runge-Kutta法のCプログラム例 で、C言語によるプログラム例が見られる。
| runge-kutta.c |
/*
* runge-kutta.c (Runge-Kutta method for Malthusian model)
*/
#include <stdio.h>
double a = 1.0;
int main(void)
{
int i, N;
double t, x, dt, k1, k2, k3, k4;
double f(double, double), x0;
double Tmax;
// 初期値
x0 = 1.0;
// 最終時刻
Tmax = 1.0;
// 時間刻み
printf("# N: "); scanf("%d", &N);
dt = Tmax / N;
// 初期値
t = 0.0;
x = x0;
printf("# t x\n");
printf("%f %f\n", t, x);
// Runge-Kutta 法
for (i = 0; i < N; i++) {
k1 = dt * f(x, t);
k2 = dt * f(x + k1/2, t + dt / 2);
k3 = dt * f(x + k2/2, t + dt / 2);
k4 = dt * f(x + k3, t + dt);
x += (k1 + 2 * k2 + 2 * k3 + k4) / 6;
t = (i + 1) * dt;
printf("%f %20.14f\n", t, x);
}
return 0;
}
double f(double x, double t)
{
return a * x;
}
|
解曲線の図を描くための手順は Euler 法のときと同様 (データファイルの名前を変えるくらい) なので省略する。
は
の近似であることを用いる。
以下の2つの課題は、プログラムとは直接の関係はなく、紙の上の数学の問題である。
(ヒント: 高校の数学IIIで学んだ
を思い出すと、
のとき
が真の解に収束することが納得できるはず。 )
Euler法、Runge-Kutta法の次数という重要な概念に触れるために、 次の研究課題に取り組むことを勧める。
この図2
をどうやって描いたか、
付録 H.2 (p.
)
に説明してある。
C プログラマー向けの説明 上の runge-kutta.c の Python バージョンは次のようになる。
| runge-kutta.py |
# runge-kutta.py --- Malthus方程式をRunge-Kutta法で解く
# Cプログラムの Python バージョン
# runge-kutta.c(http://nalab.mind.meiji.ac.jp/~mk/labo/text/ode-workbook/node11.html)
# Runge-Kutta法であるが、応用が効きにくい形。参考プログラム。
def f(x, t):
return a * x
a=1
x0=1
Tmax=1
str=input('N='); N=int(str);
dt=Tmax/N
t=0.0; x=x0
print('%f %f' % (t,x))
for i in range(N):
k1 = dt * f(x,t)
k2 = dt * f(x + k1/2, t + dt / 2)
k3 = dt * f(x + k2/2, t + dt / 2)
k4 = dt * f(x + k3, t + dt)
x += (k1 + 2 * k2 + 2 * k3 + k4) / 6
t = (i + 1) * dt
print('%f %f' % (t,x))
|
このプログラムを色々書き換えてみよう。
桂田 祐史