こういう場合は、色々な に対して一斉に を計算するプログ ラムを作るのがいいでしょう。
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 法は収束があまり速くないので、実際には特殊な場合を除いて 使われていません。そこで…