c言語で数値解析の基礎を学ぶ - miyagi university of...

21
C 言語で数値解析 1 / 21 10:38am 2005 7 19 Uryu Hitoshi C 言語で数値解析の基礎を学ぶ 2005 年度 数値解析 A *がついている項目はアドバンスです。練習問題をするためには必要ありません。 目次 1 関数の補間 2 1.1 ラグランジュ補間 ......................................... 2 1.2 *ニュートン補間 .......................................... 3 2 数値積分 4 2.1 中点公式 .............................................. 4 2.2 台形公式 .............................................. 5 2.3 シンプソンの公式 ......................................... 6 2.4 *3 つの公式の比較 ......................................... 7 3 方程式の解 8 3.1 2 次方程式 ............................................. 8 3.2 2 分法 ............................................... 10 3.3 *割線法 ............................................... 12 3.4 ニュートン法 ............................................ 13 4 関数の不動点 16 4.1 通常のプログラム ......................................... 16 4.2 *GnuPlot 用プログラム ...................................... 17 5 演習のしかた 18 5.1 C 言語プログラムの実行 ...................................... 18 5.2 *データをファイルに記録する ................................... 18 5.3 *Gnuplot の実行 .......................................... 18 5.4 *Gnuplot で視覚化 ........................................ 19 6 練習問題 21 6.1 関数の補間 ............................................. 21 6.2 数値積分 .............................................. 21 6.3 方程式の解 ............................................. 21 6.4 関数の不動点 ............................................ 21 1

Upload: others

Post on 05-Feb-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 1 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

C言語で数値解析の基礎を学ぶ2005年度 数値解析 A

*がついている項目はアドバンスです。練習問題をするためには必要ありません。

目次1 関数の補間 2

1.1 ラグランジュ補間 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.2 *ニュートン補間 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 数値積分 4

2.1 中点公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.2 台形公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.3 シンプソンの公式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2.4 *3つの公式の比較 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3 方程式の解 8

3.1 2次方程式 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3.2 2分法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3.3 *割線法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3.4 ニュートン法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

4 関数の不動点 16

4.1 通常のプログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

4.2 *GnuPlot用プログラム . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

5 演習のしかた 18

5.1 C言語プログラムの実行 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

5.2 *データをファイルに記録する . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

5.3 *Gnuplotの実行 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

5.4 *Gnuplotで視覚化 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

6 練習問題 21

6.1 関数の補間 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

6.2 数値積分 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

6.3 方程式の解 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

6.4 関数の不動点 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

1

Page 2: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 2 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

1 関数の補間y =

√xの補間値を計算しています。

1.1 ラグランジュ補間

lagrange.c

1 /∗ Laglange の補間 ∗/2 #include <stdio.h>

3 #include <math.h>

4 int main()

5 {6 float x[10], y[10];

7 float xx, pn, p;

8 int i, j;

9

10 /∗ 初期値セット ∗/11 for( i = 0; i ≤ 9; i++ ){12 xx = ( float )i;

13 x[i] = xx;

14 y[i] = sqrt( xx );

15 }16

17 xx = 4.4;

18 pn = 0;

19 for( i = 0; i ≤ 9; i++ ){20 p = y[i];

21 for( j = 1; j ≤ 9; j++ ){22 if( i 6= j ){23 p = p ∗ ( xx − x[j] ) / ( x[i] − x[j] );

24 }25 }26 pn = pn + p;

27 }28 printf( "真値 %f 補間値 %f\n", sqrt( xx ), pn );

29 return 0;

2

Page 3: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 3 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

30 } 【解説】10–15行: y =

√xの補間値を 10個入れています。

17–27行: x = 4.4の補間値を計算しています。28行: 真値と補間値を表示しています。%fのところを %-20.15fの様に変えると全体で 20桁で小数点以下 15桁分の左詰め表示をします。詳しい数値が知りたいとき利用します。

補間したい関数を変えたり、補間値の個数を変えたり、計算したい xを変えて、実験してみよう.

1.2 *ニュートン補間

なお、ラグランジュの補間との違いは計算方法だけです。

newtonint.c

1 /∗ニュートン補間∗/2 #include <stdio.h>

3 #include <math.h>

4 #define N 9

5 int main()

6 {7 float x[15], w[15];

8 float xx, kotae;

9 int i, j;

10

11 /∗ データセット ∗/12 for( i = 1; i ≤ N; i++ ){13 xx = ( float )i;

14 x[i] = xx;

15 w[i] = sqrt( xx );

16 }17

18 for( i = 1; i ≤ N; i++ ){19 for( j = N; j > i; j−− ){20 w[j] = ( w[j] − w[j − 1] ) / ( x[j] − x[j − i] );

21 }22 }23

3

Page 4: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 4 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

24 xx = 4.4;

25 kotae = w[N];

26 for( i = N − 1; i ≥ 1; i−− ){27 kotae = kotae ∗ ( xx − x[i] ) + w[i];

28 }29 printf( "近似値 %f 真値 %f\n", kotae, sqrt( xx ));

30 return 0;

31 } 【解説】11–16行: y =

√xの補間値を 10個入れています。

18–28行: x = 4.4の補間値を計算しています。29行: 真値と補間値を表示しています。

補間したい関数を変えたり、補間値の個数を変えたり、計算したい xを変えて、実験してみよう.

2 数値積分2.1 中点公式

∫ 1

0

x3dxの計算をしています。

chuteni.c

1 /∗ 中点公式∗/2 #include <stdio.h>

3 #include <math.h>

4 #define N 9000.

5

6 float f( float x )

7 {8 return x ∗ x ∗ x;

9 }10

11 int main()

12 {13 float x, y, sum, f0 = 0., fn = 1., step;

14

15 sum = 0.;

16 step = ( fn − f0 ) / (2∗N);

4

Page 5: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 5 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

17 for( x = f0 + step; x < fn; x = x + 2∗step ) sum = sum + f( x );

18 printf( "%f\n", 2∗step ∗sum );

19 return 0;

20 } 【解説】4行: N を 9000としています。6–9行: f(x) = x3 を定義しています。13行: f0 が積分の下端を、fn が積分の上端です。16行: stepは積分の範囲を 2N 等分したときの幅です。17–18行: 積分値の近似計算をして、表示しています。

積分したい関数を変えたり、等分の個数を変えたりして、積分の近似計算をしてみよう。

2.2 台形公式∫ 1

0

x3dxの計算をしています。

daikei.c

1 /∗ 台形公式 ∗/2 #include <stdio.h>

3 #include <math.h>

4 #define N 9000.

5

6 float f( float x )

7 {8 return x ∗ x ∗ x;

9 }10

11 int main()

12 {13 float x, y, sum, f0 = 0., fn = 1., step;

14

15 sum = 0.;

16 step = ( fn − f0 ) / N;

17 for( x = f0 + step; x < fn; x = x + step ) sum = sum + f( x );

18 printf( "%f\n", step / 2.∗( f( f0 ) + f( fn ) + 2.∗sum ));

19 return 0;

5

Page 6: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 6 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

20 } 【解説】4行: N を 9000としています。6–9行: f(x) = x3 を定義しています。13行: f0 が積分の下端を、fn が積分の上端です。16行: stepは積分の範囲を N 等分したときの幅です。17–18行: 積分値の近似計算をして、表示しています。

積分したい関数を変えたり、等分の個数を変えたりして、積分の近似計算をしてみよう。

2.3 シンプソンの公式∫ 1

0

x3dxの計算をしています。

symp.c

1 /∗ シンプソン ∗/2 #include <stdio.h>

3 #include <math.h>

4 #define N 9000.

5

6 float f( float x )

7 {8 return x ∗ x ∗ x;

9 }10

11 int main()

12 {13 float x, y, sum, f0 = 0., fn = 1., step;

14 int i;

15

16 sum = f( f0 ) + f( fn );

17 step = ( fn − f0 ) / N;

18 i = 1;

19 for( x = f0 + step; x < fn; x = x + step ){20 if( i % 2 == 0 ){21 sum = sum + 2.∗f( x );

22 }else{

6

Page 7: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 7 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

23 sum = sum + 4.∗f( x );

24 }25 i++;

26 }27 printf( "%f\n", step / 3.∗sum );

28 return 0;

29 } 【解説】4行: N を 9000としています。6–9行: f(x) = x3 を定義しています。13行の: f0 が積分の下端を、fn が積分の上端です。17行: stepは積分の範囲を N 等分したときの幅です。18–27行: 積分値の近似計算をして、表示しています。

積分したい関数を変えたり、等分の個数を変えたりして、積分の近似計算をしてみよう。

2.4 *3つの公式の比較

中点公式、台形公式、シンプソン公式の近似値の比較をしてみます。∫ 1

0

41 + x2

dxの計算です。真の値は π です。

numint.c

1 /∗積分公式の比較∗/2 #include <stdio.h>

3 #include <stdlib.h>

4

5 double f(double x)

6 {7 return 4 / (1 + x ∗ x);

8 }9

10 int main()

11 {12 int i, n, nmax = 32;

13 double a = 0, b = 1, h, trapezoid, midpoint, simpson;

14

15 printf(" n: 台形 中点 Simpson\n");

7

Page 8: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 8 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

16 h = b − a; trapezoid = h ∗ (f(a) + f(b)) / 2;

17 for (n = 1; n ≤ nmax; n ∗= 2) {18 midpoint = 0;

19 for (i = 1; i ≤ n; i++) midpoint += f(a + h ∗ (i − 0.5));

20 midpoint ∗= h;

21 simpson = (trapezoid + 2 ∗ midpoint) / 3;

22 printf("%5d % -20.15f % -20.15 f % -20.15f \n",

23 n, trapezoid, midpoint, simpson);

24 h / 2; trapezoid = (trapezoid + midpoint) / 2;

25 }26 return EXIT SUCCESS;

27 } 【解説】5–8行: f(x) = 4

1+x2 を定義しています。12行: nmax=32 としています。13行: a が積分の下端を、b が積分の上端です。16行: hは積分の区間幅です。17–25行: 積分値の近似計算をして、表示しています。

最初は区間の幅 hで近似計算をし、次に区間幅をその半分である h

2にして複合公式を適用しています。

以後、区間幅を次々に半分にして、h

4,h

8,

h

16,

h

32として複合公式を計算しています。

12行目の nmax=32 はこの最後の 32を表しています。

積分したい関数を変えたり、積分の範囲を変えたり、また分割数を変化させて、積分の近似計算をしてみよう。

3 方程式の解3.1 2次方程式

3.1.1 公式のまま2次方程式の解の公式を直接使った計算プログラムです。桁落ちする可能性があります。equation1.c

1 #include <stdio.h>

2 #include <math.h>

3

4 main()

5 {

8

Page 9: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 9 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

6 double a, b, c, d;

7 double x1, x2;

8 a=1;b=2;c=1;

9 d = b∗b − 4.0∗a∗c;10 if (d ≥ 0.0) {11 x1 = (−b+sqrt(d))/(2.0∗a);

12 x2 = (−b−sqrt(d))/(2.0∗a);

13 printf("x1=%-27.20f (%-27.20f)\n", x1, a∗x1∗x1+b∗x1+c);

14 printf("x2=%-27.20f (%-27.20f)\n", x2, a∗x2∗x2+b∗x2+c);

15 }16 else {17 printf("x1=N.A.\n");

18 printf("x2=N.A.\n");

19 }20 exit(0);

21 } 【解説】6行: 係数 a,b,cを入れています。9行: dは判別式です。10–15行: 判別式が負でないときの計算をしています。13行: 計算値を表示しています。最初の数は x1 で、つぎに括弧でくくられた数字は ax2

1 + bx1 + cの値です。真の解に近いと括弧内の数字が 0に近いはずです。14行: 13行目と同様に x2 に対する計算値を表示しています。16–19行: 判別式が負のときは N.A.と表示させています。

桁落ちがおこる可能性のある a, b, cを入れて、桁落ちを確認してみよう。

3.1.2 桁落ちを防ぐ工夫をしたもの解と係数の関係を用いて、桁落ちを防いでいる。equation2.c

1 #include <stdio.h>

2 #include <math.h>

3

4 main()

5 {6 double a, b, c, d;

9

Page 10: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 10 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

7 double x1, x2;

8

9 a=1;b=2;c=1;

10 d = b∗b − 4.0∗a∗c;11 if (d ≥ 0.0) {12 x1 = (fabs(b)+sqrt(d))/(2.0∗a);

13 x1 = (b<0.0)?x1:−x1;

14 x2 = c/(a∗x1);/∗桁落ちを防ぐ∗/15 printf("x1=%-27.20f (%-27.20f)\n", x1, a∗x1∗x1+b∗x1+c);

16 printf("x2=%-27.20f (%-27.20f)\n", x2, a∗x2∗x2+b∗x2+c);

17 }18 else {19 printf("x1=N.A.\n");

20 printf("x2=N.A.\n");

21 }22 exit(0);

23 } 【解説】前のプログラム equation1.cとの違いだけを述べる。

12–13行: x1 =|b|+

√d

2aを計算し,b ≥ 0のときは x1 の符号を変えている。

これは分子に引き算がでてこない工夫である。これで片方の解である x1 が計算される。14行: 解と係数の関係を用いて、他の解 x2 を計算している。

桁落ちがおこる可能性のある a, b, cを入れて、うまく計算できていることを確認してみよう。

3.2 2分法

2 分法は中間値の定理を用いる最も素朴なプログラムである。収束の速度は極めて遅いが、着実に精度は上っていく逞しいプログラムである。

√2を計算するプログラムである。

bisect.c

1 /∗ 2分法 ∗/2 #include <stdio.h>

3 #include <math.h>

4 #define e 0.000001

5 #define kukana 1.

6 #define kukanb 2.

10

Page 11: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 11 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

7

8

9 float f( float x )

10 {11 return x ∗ x − 2.;

12 }13

14 int main()

15 {16 float xa, xb,xc,y;

17 int i;

18 xa = kukana;

19 xb = kukanb;

20 for( i = 1; i ≤ 50; i++ ){21 xc = ( xa + xb ) / 2.;

22 y=f(xc);

23 printf( "%d, %f\n", i,xc );

24 if( fabs( y ) < e ){25 return 0;

26 }27 if( f( xa ) ∗ f( xc ) < 0 ){28 xb = xc;

29 }else{30 xa = xc;

31 }32 }33 printf( "解が求められませんでした\n" );

34 return 0;

35 } 【解説】4–6行: e=0.000001,kukana=1,kukanb=2としている。kukanaは最初の区間の左端であり、kukanbは最初の区間の右端である。この中に

√2があることに注意する。

9–12行: f(x) = x2 − 2としている。18–19行: xa,xbに最初の区間の端を代入している。20–32行: 2分法の計算をしている。

11

Page 12: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 12 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

区間の幅を半分にしていきますが、これは最大 50回くりかえされます。24–25行目: そのときの y = f(xc)の絶対値が eより小さくなったら、終了します。33行: 50回繰り返しても y = f(xc)の絶対値が eより大きい場合は「解が求められませんでした」と表示します。

3の 3乗根を求めてみよう。

3.3 *割線法

割線法は 2分法と同じく中間値の定理を基礎とする素朴なプログラムであるが、割線の x軸との交点をつぎつぎに求めていくため、2分法よりはるかに収束は速い。

√2を計算するプログラムである。

regula.c

1 /∗割線法∗/2 #include <stdio.h>

3 #include <math.h>

4 #define e 0.000001

5 #define kukana 1.

6 #define kukanb 2.

7

8 float f( float x )

9 {10 return( x ∗ x − 2. );

11 }12

13 int main()

14 {15 float xa, xb, xc, y;

16 int i;

17

18 xa = kukana;

19 xb = kukanb;

20 for( i = 1; i ≤ 50; i++ ){21 xc = ( xa ∗ f( xb ) − xb ∗ f( xa )) / ( f( xb ) − f( xa ));

22 y = f( xc );

23 printf( " %d, %f\n", i,xc );

24 if( fabs( y ) < e ){25 return 0;

12

Page 13: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 13 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

26 }27 if( f( xa ) ∗ f( xc ) < 0 ){28 xb = xc;

29 }else{30 xa = xc;

31 }32 }33 printf( "解が求められませんでした\n" );

34 return 0;

35 }

【解説】2 分法との違いは 21 行目である。(xa, f(xa)), (xb, f(xb)) の直線と x 軸との交点を求めていることがわ

かる。

3の 3乗根を求めてみよう。

3.4 ニュートン法

Newton法は微分を用いて、曲線の接線を求め、接線の x軸との交点をつぎつぎに求めていく方法である。誤差は前回の誤差の 2乗にほぼ比例することが理論的に知られていて、極めて収束の速度が速い。

√2を計算するプログラムである。

3.4.1 通常のプログラムnewton.c

1 /∗ニュートン法∗/2 /∗判定は関数値が 0に近いかどうかで決定する∗/3 #include <stdio.h>

4 #include <math.h>

5 #define e 0.000001

6 #define initial 2

7

8 float f( float x )

9 {10 return x ∗ x −2;

11 }12 float diff( float x )

13

Page 14: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 14 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

13 {14 return 2.∗x;

15 }16 int main()

17 {18 float xa, xb;

19 int i;

20

21 xa = initial;

22 for( i = 1; i ≤ 50; i++ ){23 xb = xa − f(xa) /diff(xa);

24 printf( "%d, %f\n", i, xb );

25 if( fabs( f(xb)) < e ){26 return 0;

27 }28 xa = xb;

29 }30 printf( "解が求まりませんでした\n" );

31 return 0;

32 }【解説】6行: initial = 2 としている。これが出発の x座標となる。8–10行: f(x) = x2 − 2としている。12–15行: f ′(x)を計算している。21行: xa = initial として、最初の点を代入している。23行: xb = xa− f(xa)

f ′(xa)を計算していることがわかる。

28行: xa を接線と x軸との交点 xb に置きなおしている。

3の 3乗根を求めてみよう。

3.4.2 *GnuPlot用プログラムGnuPlotを用いると数値データを簡単にグラフに描くことができる。通常のプログラムを少し改変することにより GnuPlot用の dataを得られるようにしたものである。

newtong.c

1 /∗ニュートン法∗/2 /∗判定は関数値が 0に近いかどうかで決定する∗/3 /∗視覚可するための gnuplot用プログラム∗/

14

Page 15: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 15 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

4 #include <stdio.h>

5 #include <math.h>

6 #define e 0.000001

7 #define initial 5.0

8

9 float f( float x )

10 {11 return x∗x−2;

12 }13 float diff( float x )

14 {15 return 2.∗x;

16 }17

18

19 int main()

20 {21 float xa, xb;

22 int i;

23

24 xa = initial;

25 for( i = 1; i ≤ 50; i++ ){26 printf( "%f %f\n",xa,f(xa));

27 xb = xa − f(xa) /diff(xa);

28 printf( "%f 0.0\n", xb);

29 printf("\n");

30 if( fabs( f(xb)) < e ){31 return 0;

32 }33 xa = xb;

34 }35 return 0;

36 }

15

Page 16: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 16 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

4 関数の不動点関数 f(x)の不動点 α (f(α) = α) を求めるプログラムである。理論的には最も簡単な不動点定理に依存している。

α = e−α となる αを求める。

4.1 通常のプログラム

iteration.c

1 /∗逐次近似法、縮小写像∗/2 #include <stdio.h>

3 #include <math.h>

4 #define begin 0.5 /∗初期値を与えるx∗/5 #define eps 0.0001 /∗逐次近似収束判定数∗/6

7 float f( float x )

8 {9 return exp(−x);

10 }11

12 int main()

13 {14 float xa, xb;

15 int i;

16

17 xa = begin;

18 for( i = 1; i ≤ 50; i++ )

19 {20 xb = f(xa);

21 printf( "%f\n", xb );

22 if( fabs(xa−xb) < eps )

23 {24 printf( "%f\n",xb );

25 return 0;

26 }27 xa = xb;

16

Page 17: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 17 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

28 }29 printf( "解が求まりませんでした\n" );

30 return 0;

31 }【解説】4行: begin = 0.5となっているので、これが出発となる x座標である。7–10行: f(x) = e−x としている。17行: xa = beginで出発点となる x座標を代入している。18–28行: 実際の繰り返し計算である。xb = f(xa)を計算し、|xa− xb| < epsとなったら、終了する。29行: 50回繰り返しても |xa− xb| ≥ epsの場合は「解が求められませんでした」と表示します。

4.2 *GnuPlot用プログラム

iterationg.c

1 /∗逐次近似法、縮小写像∗/2 /∗逐次近似を視覚可するための gnuplot用プログラム∗/3 #include <stdio.h>

4 #include <math.h>

5 #define begin 1.0 /∗初期値を与えるx∗/6 #define eps 0.0001 /∗逐次近似収束判定数∗/7

8 float f( float x )

9 {10 return exp(−x);

11 }12

13 int main()

14 {15 float xa, xb;

16 int i;

17

18 xa = begin;

19 for( i = 1; i ≤ 50; i++ )

20 {21 xb = f(xa);

22 printf( "%f, %f\n", xa,xa );

17

Page 18: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 18 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

23 printf( "%f, %f\n", xa,xb );

24 if( fabs(xa−xb) < eps )

25 {26 return 0;

27 }28 xa = xb;

29 }30 return 0;

31 }

5 演習のしかた5.1 C言語プログラムの実行

説明の都合上、Unix プロンプトを ∗ ∗ ∗ > と書くことにする。

以下、実行のさせる Cプログラムが sample.c であるとして説明する。∗ ∗ ∗ > gcc -lm sample.c

でコンパイルする。実行は∗ ∗ ∗ > ./a.out

muleなどでプログラムを適宜書き直して実験することになります。

5.2 *データをファイルに記録する

データを表示するプログラムの場合は、これをファイルに記録することができる。このときは次のようにする。∗ ∗ ∗ > ./a.out > test.dat

で test.datに書き出すことができる。

5.3 *Gnuplotの実行

説明の都合上、gnuplot プロンプトを gnuplot > と書くことにする。

次に gnuplotの使い方を説明する。これには二つの方法がある。一つは直接データファイルのグラフを描かせることであり、このときは次の命令を叩く。データファイルが

test.datであるとして説明する。

gnuplot > plot ”test.dat” with lines

で test.datのデータを線で結んで描く。

gnuplot > plot ”test.dat” with dots

で test.datのデータを点で描く。

18

Page 19: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 19 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

もう一つは命令を記述したテキストファイルを実行させることである。通常これを gnuplotのスクリプトと呼んでいる。今スクリプトが view.gpであったとして説明する。

gnuplot > load ”view.gp”

で view.gpに記述された gnuplotの命令が順次実行される。

5.4 *Gnuplotで視覚化

5.4.1 newtong.c の使い方∗ ∗ ∗ > gcc -lm newtong.c

でコンパイルする。∗ ∗ ∗ > ./a.out > newton.dat

で newton.datに書き出す。gnuplot > plot x*x -2

で y = x2 − 2のグラフを描く。gnuplot > replot 0

で y = 0すなわち x軸を描く。gnuplot > replot ”newton.dat” with lines

で y = x2 − 2の接線をつぎつぎに描く。

5.4.2 iterationg.c の使い方∗ ∗ ∗ > gcc -lm iterationg.c

でコンパイルする。∗ ∗ ∗ > ./a.out > iteration.dat

19

Page 20: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 20 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

で iteration.datに書き出す。gnuplot > plot exp(-x)

で y = e−x のグラフを描く。gnuplot > replot x

で y = xのグラフを描く。gnuplot > replot ”iteration.dat” with lines

で点が近づいていく様子を描く。

20

Page 21: C言語で数値解析の基礎を学ぶ - Miyagi University of …staff.miyakyo-u.ac.jp/~h-uri/blog/archive/lecture/su...C 言語で数値解析3 / 21 10:38am 2005 年7 月19 日Uryu

C言語で数値解析 21 / 21 10:38am 2005年 7月 19日 Uryu Hitoshi

6 練習問題6.1 関数の補間

f(x) = 11+0.25x2 の [0, 10]における補間を考える。x = 0, 1, 2, · · · , 10における値をラグランジュの補間値

として、x = 9における近似値を計算をし、真の値と比較せよ。

参考プログラム: lagrange.c

6.2 数値積分

f(x) = e−x22 と置く。∫ ∞

−∞f(x)dxは

∫ 8

−8

f(x)dxでほぼ近似できることが知られている。

この積分の値を台形公式で求め、√

2π と比較してみよ。

補足:C言語で√

2π は sqrt(8*atan(1))で計算できる。また、exp(−x2)は C言語で exp(-x*x/2)と書けばよい。参考プログラム: daikei.c

6.3 方程式の解

f(x) = x3 − 11000

と置くとき、方程式 f(x) = 0の実根を数値的に求めたい。これを 2分法とニュートン法により求め、その優劣を比較してみよ。

補足:真の解は x = 0.1である。参考プログラム: bisect.c,newton.c

6.4 関数の不動点

ケプラーの方程式m = x− E sinxを解きたい。f(x) = m + E sinxと置くと、不動点 x = f(x)を求めることに帰着する。m = 0.8, E = 0.2のとき、実際に不動点を求めてみよ。

補足: 解は [0, 1]の範囲にあることに注意する。また、sinxは C言語で sin(x) と書けばよい。参考プログラム: iteration.c

21