こういう場合は、色々な
に対して一斉に
を計算するプログ
ラムを作るのがいいでしょう。
| reidai5-2.c |
/*
* reidai5-2.c --- 常微分方程式の初期値問題を Euler 法で解く
* http://nalab.mind.meiji.ac.jp/~mk/program/ode_prog/reidai5-2.c
*/
#include <stdio.h>
#include <math.h>
int main(void)
{
/* 開始時刻と終了時刻 */
double a = 0.0, b = 1.0;
/* 初期値 */
double x0;
/* 変数と関数の宣言 */
double t,x,h,f(double,double),e;
int N0,N1,r,N,i;
/* 自然対数の底 e (=2.7182818284..) */
e = exp(1.0);
/* 初期値の設定 */
x0 = 1.0;
/* どういう N について計算するか?
* N0 から N1 まで、r をかけて増える N に */
printf("# FIRSTN,LASTN,r=");
scanf("%d%d%d", &N0,&N1,&r);
/* 計算の開始 */
for (N = N0; N<= N1; N *= r) {
h = (b-a)/N;
/* 開始時刻と初期値のセット */
t = a;
x = x0;
/* Euler 法による計算 */
for (i = 0; i < N; i++) {
x += h * f(t,x);
t += h;
}
printf("%d %e\n", N, fabs(e-x));
}
return 0;
}
/* 微分方程式 x'=f(t,x) の右辺の関数 f の定義 */
double f(double t, double x)
{
return x;
}
|
コンパイルして実行すると “ FIRSTN,LASTN,r=” と尋ねてきます。
例えば “10 1280 2” と答えると、
から始めて
倍ずつしていって
を超えないまでの値
(つまり
,
,
,
,
,
,
,
)
を
として計算して、最終的に得られた誤差を出力します。
実行結果を見てみましょう。
| コンパイル&実行 |
oyabun% gcc -o reidai5-2 reidai5-2.c -lm oyabun% ./reidai5-2 # FIRSTN,LASTN,r=10 1000 2 10 1.245394e-01 20 6.498412e-02 40 3.321799e-02 80 1.679689e-02 160 8.446252e-03 320 4.235185e-03 640 2.120621e-03 1280 1.061069e-03 oyabun% |
出力結果を保存して作ったファイル “reidai5-2.data” の内容を gnuplot でグラフにするには、 以下のようにします。 両側対数目盛によるグラフを描く機能を用いています。
oyabun% ./reidai5-2 > reidai5-2.data 10 1280 2 oyabun%これで計算結果を reidai5-2.data に記録できた。 この内容を gnuplot でプロットする。
oyabun% gnuplot
G N U P L O T
Unix version 3.7
(以下色々なメッセージ…省略)
gnuplot> set logscale xy
gnuplot> plot "reidai5-2.data" with linespoints
(以下印刷用のデータ作り)
gnuplot> set term postscript eps color
Terminal type set to 'postscript'
Options are 'eps noenhanced color dashed defaultplex "Helvetica-Ryumin"
14'
gnuplot> set output "reidai5-2.eps"
gnuplot> replot
gnuplot> quit
oyabun%
|
(2021/4/1追記: ここでは EPS (Encapsulated PostScript) 形式にしていますが、 現在では set term png や set term pdf とする方が良いかも。)
このグラフから、誤差
であることが読み
とれます。実はこれは Euler 法の持つ一般的な性質です。
実は Euler 法は収束があまり速くないので、実際には特殊な場合を除いて 使われていません。そこで…