常微分方程式の初期値問題の数値解法のうち、 比較的簡単で、高精度な解が得られるため、良く用いられる方法として 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)) |
このプログラムを色々書き換えてみよう。
桂田 祐史