2 非線型方程式

2.1 概要

非線形方程式2

$\displaystyle f(x)=0$ (1)

の解の値が必要になることが,工学の問題でしばしばある.工学の問題では,数学でやったよう な厳密な解の必要はなく,精度の良い近似解で良いことが多い.近似解といっても, $ 10^{-10}$程度の精度のことを言っており,この程度の近似解が必要となる.

この非線形方程式は,図1のように$ y= f(x)$のx軸と交わる点 に実数解を持つ.ここだけとは限らないが,少なくともこの交わる点は解である.この点 の値は,コンピューターを用いた反復(ループ)計算により探すことができる.

この授業では4通りの計算テクニックを学習したが,重要3なのは

  1. 2分法
  2. ニュートン-ラフソン法(ニュートン法)
である.
図 1: $ f(x)=x^3-3x^2+9x-8$の関数.x軸との交点が解である.
\includegraphics[keepaspectratio, scale=0.7]{figure/function_solution/ShapeOfFunction.eps}

2.2 二分法(bisection method)

2.2.1 計算方法

閉区間$ [a,\,b]$で連続な関数$ f(x)$の値が,

$\displaystyle f(a)f(b)<0$ (2)

ならば, $ f(\alpha)=0$となる$ \alpha$が区間$ [a,\,b]$にある.

実際の数値計算は, $ f(a)f(b)<0$であるような2点 $ a,\,b(a<b)$から出発する. そして,区間$ [a,\,b]$を2分する点$ c=(a+b)/2$に対して,$ f(c)$を計算を行う. $ f(c)f(a)<0$ならば$ b$$ c$と置き換え, $ f(c)f(a)>0$ならば$ a$$ c$と置き 換える.絶えず,区間$ [a,b]$の間に解があるようにするのである.この操作 を繰り返して,区間の幅$ \vert b-a\vert$が与えられた値 $ \varepsilon$ よりも小さく なったならば,計算を終了する.解へ収束は収束率1/2の一次収束である.

実際にこの方法で

$\displaystyle x^3-3x^2+9x-8=0$ (3)

を計算した結果を図2に示す.この図より,$ f(a)$$ f(b)$の関係 の式(2)を満たす区間$ [a,b]$が1/2ずつ縮小していく様子がわかる.この 方法の長所と短所は,以下の通りである.
長所
閉区間$ [a,b]$に解があれば,必ず解に収束する.間違いなく解 を探すので,ロバスト(robust:強靭な)な解法と言われている. 次に示すニュートン法とは異なり,連続であればどんな形の関数 でも解に収束するので信頼性が高い方法と言える.さらに,解の 精度も分かり便利である.解の誤差は,区間の幅$ \vert b-a\vert$以下で る.
短所
収束が遅い(図6).一次収束である.
図 2: $ f(x)=x^3-3x^2+9x-8$の実数解を2分法で解散し,その解の収束の 様子を示している.初期値は $ a=-1,\,b=11$として,最初の解$ c=x_0=5$が求 まり,順次より精度の良い $ x_1,\,x_2,\,x_3,\cdots$が求まる.それが,解析解 $ x=1.1659\cdots $(x軸との交点)に収束していく様子が分かる.
\includegraphics[keepaspectratio, scale=0.7]{figure/function_solution/NibunMethod.eps}

2.2.2 アルゴリズム

関数はあらかじめ,プログラム中に書くものとする.更に,計算を打ち切る条 件もプログラム中に書くものとする.そうすると,図 3のような2分法のフローチャートが考えられる.
図 3: 2分法のフローチャート
\includegraphics[keepaspectratio, scale=1.0]{figure/flow_chart/flow_nibun.eps}

2.2.3 プログラム

このプログラムを暗記する必要はない.テストでは,アルゴリズム上,重要な部分を虫食 いにして出題するつもりである(たぶん).
   1 #include <stdio.h>
   2 double func(double x);
   3 
   4 /*=============================================================*/
   5 /*       main function                                         */
   6 /*=============================================================*/
   7 
   8 int main(){
   9   double eps=1e-15;         /* precision of calculation */
  10   double a, b, c;
  11   double test;
  12   char temp;
  13   int i=0;
  14 
  15   do{
  16 
  17     printf("\ninitial value a = ");
  18     scanf("%lf%c", &a, &temp);
  19 
  20     printf("initial value b = ");
  21     scanf("%lf%c", &b, &temp);
  22 
  23     test=func(a)*func(b);
  24 
  25     if(test >= 0){
  26       printf("   bad initial value !!  f(a)*f(b)>0\n\n");
  27     }
  28 
  29   }while(test >= 0);
  30 
  31   if(b-a<0){
  32     c=a;
  33     a=b;
  34     b=c;
  35   }
  36 
  37 
  38   while(b-a>eps){
  39 
  40     c=(a+b)/2;
  41 
  42     if(func(c)*func(a)<0){
  43       b=c;
  44     }else{
  45       a=c;
  46     }
  47 
  48     i++;
  49     printf(" %d\t%20.15f\n",i,c);
  50 
  51   }
  52 
  53   printf("\nsolution x = %20.15f\n\n",c);
  54 
  55   return(0);
  56 }
  57 
  58 
  59 /*=============================================================*/
  60 /*       define function                                       */
  61 /*=============================================================*/
  62 
  63 double func(double x){
  64   double y;
  65 
  66   y=x*x*x-3*x*x+9*x-8;
  67 
  68   return(y);
  69 }

2.3 実数解のニュートン法(Newton's method)


2.3.1 計算方法

関数$ f(x)$のゼロ点$ \alpha$に近い近似値$ x_0$から出発する.そして,関数 $ f(x)$上の点 $ (x_0,f(x_0))$での接線が,x軸と交わる点を次の近似解$ x_1$ とする.そして,次の接線がx軸と交わる点を次の近似解$ x_2$とする.同じこ とを繰り返して $ x_3,\,x_4,\cdots$を求める(図4).こ の計算結果の数列 $ (x_0,\,x_2,\,x_3,\,x_4,\cdots)$は初期値$ x_0$が適当で あれば,真の解$ \alpha$に収束する.

まずは,この数列の漸化式を求める.関数$ f(x)$上の点 $ (x_i,\,f(x_i))$の接 線を引き,それとx軸と交点$ x_{i+1}$ である.まずは,$ x_{i+1}$ を求める ことにする.点 $ (x_i,\,f(x_i))$を通り,傾きが $ f^\prime(x_i)$の直線の方 程式は,

$\displaystyle y-f(x_i)=f^\prime(x_i)(x-x_i)$ (4)

である.$ y=0$の時の$ x$の値が$ x_{i+1}$にである.$ x_{i+1}$は,

$\displaystyle x_{i+1}=x_i-\frac{f(x_i)}{f^\prime(x_i)}$ (5)

となる.$ x_i$から$ x_{i+1}$計算できる.これをニュートン法の漸化式と言う. この漸化式を用いれば,次々と近似解を求めることができる.

計算の終了は,

$\displaystyle \left\vert\frac{x_{i+1}-x_i}{x_i}\right\vert<\varepsilon$ (6)

の条件を満たした場合とするのが一般的である. $ \varepsilon$は計算精度を 決める定数で,非常に小さな値である.これ以外にも計算の終了を決めること は可能である.必要に応じて,決めればよい.実際に式 (3)を計算した結果を図4に 示す.接線との交点が解に近づく様子がわかるであろう.

ニュートン法を使う上で必要な式は,式(5)のみで ある.計算に必要な式は分かったが,数列がどのように真の解$ \alpha$に収束 するか考える.$ x_{i+1}$ と真値$ \alpha$の差の絶対値,ようするに誤差を 計算する. $ f(\alpha)=0$を忘れないで,テイラー展開を用いて,計算を進める と

\begin{equation*}\begin{aligned}\vert\alpha-x_{i+1}\vert &=\left\vert\alpha-x_i+...
...=\left\vert O\left((\alpha-x_i)^2\right)\right\vert \end{aligned}\end{equation*}

となる.$ i+1$番目の近似値は,$ i$番目に比べて2乗で精度が良くなるのであ る.これを,二次収束と言い,非常に早く解に収束する.例えば,$ 10^{-3}$ の精度で近似解が得られているとすると,もう一回式 (5)を計算するだけで,$ 10^{-6}$程度の精度で近似 解が得られるということである.一次収束の2分法よりも,収束が早いことが 分かる.

ニュートン法の特徴をまとめると次のようになる.

長所
初期値が適当ならば,収束が非常に早い(図 6).
短所
初期値が悪いと,収束しない(図7).収束 しない場合があるので,反復回数の上限を決めておく必要がある.
図 4: $ f(x)=x^3-3x^2+9x-8$の実数解をニュートン法で計算し,解の収 束の様子を示している.初期値$ x_0=5$から始まり,接線とx軸の交点からよ り精度の高い回を求めている.
\includegraphics[keepaspectratio, scale=0.7]{figure/function_solution/NewtonMethod.eps}

2.3.2 アルゴリズム

2分法同様,関数と計算を打ち切る条件はプログラム中に書くものとする.そ うすると,図5のようなニュートン法のフローチャー トが考えられる.
図 5: ニュートン法のフローチャート
\includegraphics[keepaspectratio, scale=1.0]{figure/flow_chart/flow_newton.eps}

2.3.3 プログラム

このプログラムを暗記する必要はない.テストでは,アルゴリズム上,重要な部分を虫食 いにして出題するつもりである(たぶん).
   1 #include <stdio.h>
   2 #include <math.h>
   3 #define IMAX 50
   4 double func(double x);
   5 double dfunc(double x);
   6 
   7 /*================================================================*/
   8 /*       main function                                            */
   9 /*================================================================*/
  10 int main(){
  11   double eps=1e-15;         /* precision of calculation */
  12   double x[IMAX+10];
  13   char temp;
  14   int i=-1;
  15 
  16   printf("\ninitial value x0 = ");
  17   scanf("%lf%c", &x[0], &temp);
  18 	
  19   do{
  20     i++;
  21     x[i+1]=x[i]-func(x[i])/dfunc(x[i]);
  22 
  23     printf("  %d\t%e\n", i, x[i+1]);
  24 
  25     if(fabs((x[i+1]-x[i])/x[i])<eps) break;
  26   }while(i<=IMAX);
  27 
  28   if(i>=IMAX){
  29     printf("\n  not converged !!! \n\n");
  30   }else{
  31     printf("\niteration = %d  solution  x = %20.15f\n\n",i,x[i+1]);
  32   }
  33 
  34   return(0);
  35 }
  36 
  37 /*================================================================*/
  38 /*       define function                                          */
  39 /*================================================================*/
  40 double func(double x){
  41   double y;
  42 
  43   y=x*x*x-3*x*x+9*x-8;
  44 
  45   return(y);
  46 }
  47 
  48 /*================================================================*/
  49 /*       define derived function                                  */
  50 /*================================================================*/
  51 double dfunc(double x){
  52   double dydx;
  53 
  54   dydx=3*x*x-6*x+9;
  55 
  56   return(dydx);
  57 }

2.4 ニュートン法と2分法の比較

2.4.1 解への収束速度

6に,二分法とニュートン法の解への近 づき具合を示す.二分法に比べ,ニュートン法が解への収束が早いことがわかる.前者は 二次収束で,後者は一次収束であることがグラフより分かる.二分法は,10回の計算で, $ 2^{-10}=1/1024$程度になっている.

二分法に比べて,ニュートン法は収束が早く良さそうであるが,次に示すように解へ収束 しない場合があり問題を含んでいる.

図 6: 二分法とニュートン法の計算回数(反復回数)と誤差の関係
\includegraphics[keepaspectratio, scale=0.7]{figure/Graph/Bisection_Newton.eps}

2.5 ニュートン法の問題点

アルゴリズムから,2分法は解に必ず収束する.ただし,この方法は,収束のスピードが 遅く,それが欠点となっている.一方,ニュートン法は解に収束するとは限らない.初期 条件に依存する場合がある.厳密にその条件を求めるのは大変なので,初期条件により収 束しない実例を示す.

非線形方程式

$\displaystyle 3\tan^{-1}(x-1)+\frac{x}{4}=0$ (8)

の解を計算することを考える.これは,初期値のより,収束しない場合がある.例えば初 期値$ x_0=3$の場合,図7のように収束しない.これを初期値 $ x_0=2.5$にすると図8のように収束する.

このようにニュートン法は解に収束しないで,振動する場合がある.こうなる と,プログラムは無限ループに入り,永遠に計算し続ける.これは資源の無駄 遣いなので,慎むべきである.通常は,反復回数の上限を決めて,それを防ぐ. ニュートン法を使う場合は,この反復回数の上限は必須である.

実際には収束しない場合のほうが稀であるので,ニュートン法は非常に強力な 非線型方程式の解法である.ただ,反復回数の上限を決めることを忘れてはならない.

図 7: ニュートン法で解が求まらない場合
\includegraphics[keepaspectratio, scale=0.7]{figure/comv_hasan/hasan.eps}
図 8: ニュートン法で解が求まる場合
\includegraphics[keepaspectratio, scale=0.7]{figure/comv_hasan/comb.eps}


ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成18年10月2日


no counter