微分方程式の数値解析 #6
落体の運動方程式をRK4により数値的に解くFORTRANプログラム。
Euler法によるプログラムのうちy(t)とv(t)からy(t+h)とv(t+h)を求める漸化式部分をRK4に変更しただけ。
同じ計算をnextyとnextvで行っているのでおいしくないプログラムになっている。
もっとまとめられて綺麗になるはずだが面倒なのでこのままで。
...snip double precision function nexty(t, y, v, h) double precision, intent(in) :: t, y, v, h double precision :: ky1, ky2, ky3, ky4, kv1, kv2, kv3, kv4 ky1 = f1(t, y, v) kv1 = f2(t, y, v) ky2 = f1(t + h / 2, y + h / 2 * ky1, v + h / 2 * kv1) kv2 = f2(t + h / 2, y + h / 2 * ky1, v + h / 2 * kv1) ky3 = f1(t + h / 2, y + h / 2 * ky2, v + h / 2 * kv2) kv3 = f2(t + h / 2, y + h / 2 * ky2, v + h / 2 * kv2) ky4 = f1(t + h, y + h * ky3, v + h * kv3) kv4 = f2(t + h, y + h * ky3, v + h * kv3) nexty = y + h / 6 * (ky1 + 2 * ky2 + 2 * ky3 + ky4) end function nexty double precision function nextv(t, y, v, h) double precision, intent(in) :: t, y, v, h double precision :: ky1, ky2, ky3, ky4, kv1, kv2, kv3, kv4 ky1 = f1(t, y, v) kv1 = f2(t, y, v) ky2 = f1(t + h / 2, y + h / 2 * ky1, v + h / 2 * kv1) kv2 = f2(t + h / 2, y + h / 2 * ky1, v + h / 2 * kv1) ky3 = f1(t + h / 2, y + h / 2 * ky2, v + h / 2 * kv2) kv3 = f2(t + h / 2, y + h / 2 * ky2, v + h / 2 * kv2) ky4 = f1(t + h, y + h * ky3, v + h * kv3) kv4 = f2(t + h, y + h * ky3, v + h * kv3) nextv = v + h / 6 * (kv1 + 2 * kv2 + 2 * kv3 + kv4) end function nextv ...snip
での結果は、
0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 ...snip 1.00000000 4.90332508 4.90332508 9.80665016 9.80665016 ...snip 2.00000000 19.61330032 19.61330032 19.61330032 19.61330032
であり、落下距離も落下速度も真値に一致する。
ところで、この方程式についてはRK4では時間の刻み幅に無関係に誤差は無いわけであるから、
繰り返し計算による計算誤差の累積を考えれば、
刻み幅は必要な時刻の値だけが得られる程度に大きい方がよいことになる。
で10[s]まで計算すると、
0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 1.00000000 4.90332508 4.90332508 9.80665016 9.80665016 2.00000000 19.61330032 19.61330032 19.61330032 19.61330032 3.00000000 44.12992573 44.12992573 29.41995049 29.41995049 4.00000000 78.45320129 78.45320129 39.22660065 39.22660065 5.00000000 122.58312702 122.58312702 49.03325081 49.03325081 6.00000000 176.51970291 176.51970291 58.83990097 58.83990097 7.00000000 240.26292896 240.26292896 68.64655113 68.64655113 8.00000000 313.81280518 313.81280518 78.45320129 78.45320129 9.00000000 397.16933155 397.16933155 88.25985146 88.25985146 10.00000000 490.33250809 490.33250809 98.06650162 98.06650162
となる。
とはいえ、刻み幅1e-3[s]程度では10[s]の値はこの1[s]の時と変わらず誤差は見られなかった。
刻み幅1e-6[s]でやっと
...snip 10.00000000 490.33250806 490.33250809 98.06650160 98.06650162
この程度の誤差が現れる。
累積誤差だけでなく計算時間的な問題もあるので、
刻み幅が大きくても構わないのであれば大きくすべきであろう。