方程式の反復解法 (2)

C プログラミング
第4回
— 方程式の反復解法 (2) —
基幹理工学部
1/12
復習
ファイル名:041.c
ニュートン法を用いて方程式 f (x) = cos x − x2 = 0 の
0 < x < 1 の範囲にある解の近似値(小数点以下6位まで)
を求めよ.初期値 x(0) は 1.0 とし,表記は以下のようにせよ.
initial value: 1
x(001) = ...
x(002) = ...
...
answer = ...
▶
▶
▶
右は f (x) の図.
f ′ (x) = − sin x − 2x.
前回作ったプログラム
のどこを直せばよいか
を考えよ.
2/12
ニュートン法のプログラム
▶
方程式 f (x) = 0 に対して,二つの関数
double func(double x)
→ 関数 f (x)
double func_d(double x) → 導関数 f ′ (x)
を定義している.
▶
▶
▶
⇓
関数 f (x) が複雑な場合,導関数 f ′ (x) の計算が面倒に
なる.
導関数の記述を間違える可能性がある.
⇓
数値微分を行うことにより,f (x) から自動的に微分値
f ′ (x) の近似を計算する.
3/12
ニュートン法のプログラム
▶
方程式 f (x) = 0 に対して,二つの関数
double func(double x)
→ 関数 f (x)
double func_d(double x) → 導関数 f ′ (x)
を定義している.
▶
▶
▶
⇓
関数 f (x) が複雑な場合,導関数 f ′ (x) の計算が面倒に
なる.
導関数の記述を間違える可能性がある.
⇓
数値微分を行うことにより,f (x) から自動的に微分値
f ′ (x) の近似を計算する.
3/12
ニュートン法のプログラム
▶
方程式 f (x) = 0 に対して,二つの関数
double func(double x)
→ 関数 f (x)
double func_d(double x) → 導関数 f ′ (x)
を定義している.
▶
▶
▶
⇓
関数 f (x) が複雑な場合,導関数 f ′ (x) の計算が面倒に
なる.
導関数の記述を間違える可能性がある.
⇓
数値微分を行うことにより,f (x) から自動的に微分値
f ′ (x) の近似を計算する.
3/12
数値微分
1変数関数 f (x) に対しての微分の定義は
f (x + h) − f (x)
h→0
h
f ′ (x) = lim
である.
この代わりに,有限の小さい正数 h を用いて
f ′ (x) ≈
f (x + h) − f (x)
h
により微分値の近似を計算する方法を数値微分という.
4/12
数値微分
▶
数値微分を行う際の刻み幅 h の値を適当な微小値(例
えば h = 1e − 4)として定義することで,ニュートン法
のプログラムは例えば,以下のように変更できる.
int main(void){
…
i=0;
while (i<max){
f = func(x);
df = func_d(x);
x_n= x- f/df;
…
}
…
return 0;
}
int main(void){
…
h=1e-4;
i=0;
while (i<max){
f = func(x);
df = (func(x+h)-func(x))/h;
x_n= x- f/df;
…
}
…
return 0;
⇒
}
5/12
演習
ファイル名:042.c
041.c を修正して f ′ (x) の箇所を数値微分を用いたものに書
き変えよ.初期値 x(0) = 1.0 とし,表記は以下のようにせよ.
initial value: 1
x(001) = ...
x(002) = ...
...
answer = ...
▶
右の図は,
f (x) = cos x − x2 のグ
ラフである.
6/12
前項で作成したプログラムでは…
double func(double x){
return x - cos(x);
}
double NewtonRaphson(double x0, double e, int max){
…
i=0;
while(i<max){
f = func(x);
df = (func(x+h)-func(x))/h;
…
}
▶
▶
方程式を表す関数 func( ) をそのままニュートン法を行
う関数 newton( ) の中で利用している.
⇓
方程式を表す関数が別の名前(例えば,func2( )) で与
えられたとき,関数 newton( ) の中身も修正する必要が
ある.
7/12
前項で作成したプログラムでは…
double func(double x){
return x - cos(x);
}
double NewtonRaphson(double x0, double e, int max){
…
i=0;
while(i<max){
f = func(x);
df = (func(x+h)-func(x))/h;
…
}
▶
▶
方程式を表す関数 func( ) をそのままニュートン法を行
う関数 newton( ) の中で利用している.
⇓
方程式を表す関数が別の名前(例えば,func2( )) で与
えられたとき,関数 newton( ) の中身も修正する必要が
ある.
7/12
前項で作成したプログラムでは…
double NewtonRaphson(double x0, double e, int max){
…
i=0;
while(i<max){
f = func2(x);
df = (func2(x+h)-func2(x))/h;
…
}
double func2(double x){
return x - cos(x);
}
⇓
関数へのポインタを利用することで.方程式を表す関数名
を newton( ) への引数として渡すことができる.
例: newton (func2,1.0,1e-6,100);
8/12
関数へのポインタ
▶
▶
▶
▶
変数や配列と同様に,関数もメモリ上のどこかに配置
される.つまり,変数や配列と同様,関数にもアドレス
が与えられる.
配列名は,プログラム中では配列の先頭要素へのポイ
ンタに読み替えられていた.
同様に,関数名はプログラム中では関数へのポイン
タへと読み替えられる.
例えば,関数
double function(double x){
…
}
が定義されているとき,関数名 function は関数
function( ) の先頭アドレスを指す.
9/12
関数へのポインタ(プログラム例)
#include <stdio.h>
double add(double x, double y){
return x+y;
}
double sub(double x, double y){
return x-y;
}
int main(void){
double (*func_p)(double,double);
/* func_p は2つの double 型の引数 */
/* 関数へのポインタとして定義. */
func_p = add;
/* func_p に関数 add へのポインタを代入 */
printf("%fY
=n",func_p(3.0,2.0));
func_p = sub;
/* func_p に関数 sub へのポインタを代入 */
printf("%fY
=n",func_p(3.0,2.0)); return 0;
}
10/12
演習
ファイル名: 043.c
単位円 x2 + y 2 = 1 と直線 y = x + 1/2 の2つの交点の座標の近似解
(小数点以下第6位まで)を求めるプログラムを次の事実を元に作りな
√
さい: 単位円 x2 + y 2 = 1 は y = ± 1 − x2 という2つの関数.点の x
座標は,以下の2つの関数の零点である.
√
√
f (x) = x + 1/2 − 1 − x2 ,
g(x) = x + 1/2 + 1 − x2
2
2
x +y =1
1.5
1
y
0.5
0
-0.5
-1
-1.5
-1.5
-1
-0.5
0
x
0.5
1
1.5
11/12
演習
ファイル名:043.c
▶
▶
▶
▶
前頁のことを踏まえて,単位円 x2 + y 2 = 1 と直線
y = x + 1/2 の交点の近似解を求めるプログラムを作れ.
数値微分,関数へのポインタは必ず使うこと.
ニュートン・ラプソン法を用いる際の ε, IM AX はそれぞ
れ ε = 10−6 , IM AX = 20 とせよ.初期値は f (x) に対し
ては x0 = 0,g(x) に対しては x0 = −1 とせよ.
結果の表示は以下のようにせよ.
Newton-Raphson method:
Upper part: ( ?????, ????? )
Lower part: ( ?????, ????? )
12/12