Processing math: 83%

情報基礎A 「Cプログラミング」(ステップ4・ニュートン法)

このページは、方程式の数値解を反復によって求める方法について考える。

1.反復によって方程式を解く

二次方程式 x2x1=0 の解を求める方法について考えてみよう。もちろん我々は解の公式を知っているので、直ちに x=1±52 で一件落着なのだが、仮に、解の公式を知らず、しかも、数値的に値が求まれば十分、といったケースをここでは想定する。 事実、世の中には「解の公式」が無い(まだ見つかっていない、仮に見つかったとして複雑すぎて使えない、あるいは、公式そのものが存在しない)場合がほとんどである。

まず、元々の方程式を少し変形して x=1+1x と書き直してみる。そして、その右辺と左辺をそれぞれ x の関数だと思ってプロットすると、以下のようになる(茶色がx、青が1+1/x)。

c-4-sup-quad-eq-solution

このとき、二つの線の交点の x の値を求めることができれば、方程式が解けたことになる。

このような方法は一般に反復法と呼ばれ、実用的な数値計算のアルゴリズムのかなりは、反復法に分類できる。

そのアルゴリズムは案外と単純である:

実は、このパターンの計算はすでに登場していて、連分数

c-4-eq-cont-frac-golden-ratio

例題プログラム4cが、まさに「これ」である。

ここで、注意深い諸君は、上の計算では二次方程式の2つの解のどちらが求まるのか(あるいは両方求まるのか)が気になるだろう。 それについて考えるため、「まず x の出発値を選んでおいてから、1+1/x を新しい x だと考えて繰り返す」というプロセスを図で表してみたのが以下である。 波線は出発値のセット、矢印付きの線分は反復を表している。 図の左側では反復の度に交点から遠ざかる一方で、右側では値が交点に収束するように見える。

y=1+1/xy の高さが x に対応するので、 そこから水平線を横に伸ばして、y=x との交点の位置を求め、 その点での x の値を次の計算ステップの出発値 にすれば、 xx とおいて、次の反復へと進んだことになる。

c-4-iteration-sup-quad-eq-fixed-points

つまり、上記の計算法によって求めることができるのは、解のうち片方(図で右側の(1+5)/2)だけなのだ。

この違いは、交点 x=x での関数 y(x)=1+1/x の傾きの大きさによって決まり、(以下で述べるように)|y(x)|<1 であれば、値が交点(固定点と呼ぶ)に収束することがわかる。

この方法はエレガントさは欠くものの、力業で結果を得たい場合には、案外と便利である。

以上で述べた方程式を解くための手順を、もう少し一般化してまとめると、

となる。

* ということは、x=y(x) のパターンの作り方を工夫することで、別の解まで探し出すことができる可能性がある。 例えば、上の二次方程式の例では、z=1/x と変数変換してから、z1/z1 を反復すると、他方の解を得ることができる。

icon-pc 練習:非線形方程式の数値解

反復法を使って、非線形方程式 exp(x)xx+1=0 の解を求めるプログラムを作成し、動作を確認せよ。

icon-hint ヒント

解は x=1.349976485 、および x=0.8064659942 である。

icon-teacher 解説 : 固定点の安定性

解くべき方程式 x=y(x) を見ると、これは、関数 y(x) の値が再び x になっている状態を探すことに他ならず、 そのような x=xy(x) の固定点(fixed point)と呼ばれる。 いま、反復の過程で、固定点の近くの x=x+δ の状態にあったとすると、次の反復では、値は y(x+δ) に更新される。 固定点の周りで y(x) を展開し、y(x)=x であることを思い出して、式を整理すると y(x+δ)=x+y(x)δ+O(δ2) となる。これは、最初の「ずれ」δが、反復の過程で(高次の項が無視できるような状況では) δy(x)δ と変換されることに対応する。つまり、n回の反復で、「ずれ」は (y(x))nδ のように変化することになるので、 それが0に収束するための条件(あるいは、固定点が安定である条件)は |y(x)|<1 となる。


2.ニュートン法による求根

ここで、再び x2x1=0 の数値解法を考えよう。 f(x)=x2x1 とおいて、y=f(x) をプロットすると下図のようになるが、x軸とグラフの交点の位置を我々は求めたいわけである。

c-4-sup-quad-eq-newton1

この種の問題に対しては、ニュートン法Newton's method)と呼ばれる、非常に効率のよい反復法のアルゴリズムが知られている。 その手順はそれほど難しいものではない:

ニュートン法

ここで、より具体的な計算手順を得るために、n 回目の反復の際の x の値を xn と置いて、反復の過程を考えてみよう。 まず、ステップ2〜4の反復の様子を図で表すと、次のようになる。赤線が接線である。

ニュートン法は、単純な反復法に較べ、格段に収束が速く、1回の反復あたり、精度(有効桁数)が倍になることが知られている。

c-4-sup-quad-eq-newton2

ここで、座標 (xn,f(xn)) を通り、勾配が f(xn) の直線の方程式は y=f(xn)(xxn)+f(xn) であるから、この式で y=0 とおいて、x について解くと、 x=xnf(xn)f(xn) となる。この値を、次のステップのxとするわけだから、ニュートン法の反復の「ステップ2」では、 xn+1xnf(xn)f(xn) という処理を行えばよいことが分かった。

例えば、f(x)=x2x1 の場合、その導関数は f(x)=2x1 とすぐ計算できるので、具体的なCのコードは以下のようになるだろう:

例題4c (ex4c.c)

出発値を適切に選ぶことによって、方程式の二つの解がそれぞれ計算できる。

#include <stdio.h>
#include <math.h>

main()
{
  float x,xp ;
  printf("出発値:") ;
  scanf("%f",&x) ;
  for(;;) {
    xp = x - (x*x-x-1)/(2*x-1) ;
    if (fabs(xp-x)<0.00001) break ;
    x = xp ;
  }
  printf("x= %f\n",xp) ;
}

† 電卓やパソコンで a の平方根を求める際には f(x)=x2a とおいて、実際に、内部でニュートン法による計算処理が行われている。 例えば、2を計算するために f(x)=x22 とおくと、f(x)=2xだから、ニュートン法の反復内容は xn+1xnx2n22xn=xn2+1xn となる。ここで、最初の近似値としてかなり大雑把に x1=2と置いたとしても、 x2=2/2+1/2=3/2=1.5 x3=3/4+2/3=17/12=1.41666666666666 x4=17/24+12/17=577/408=1.414215686274510 x5=577/816+408/577=665857/470832=1.414213562374690 のように、たった4回の反復で、真の値 1.41421356237309 と12桁まで一致してしまう(反復の度に、有効桁数がほぼ倍になる)。

icon-pc 練習:ニュートン法

ニュートン法を使って、非線形方程式 exp(x)xx+1=0 の解を求めるプログラムを作成し、動作を確認せよ。

icon-teacher 解説 : ニュートン法の収束性

ニュートン法で f(x)=0 の数値解を計算する際、n回目の反復を行なった時点で、解 x からまだ δ だけずれていた、すなわち、 xn=x+δ であったとしよう。

この状態で、さらに反復を続けると、次のステップでは xn+1=x+δf(x+δ)f(x+δ) となるが、関数をxの周りでテイラー展開 f(x+δ)=f(x)+f(x)δ+12f して、定義から f(x^*)=0 であることを思い出しながら、式を整理すると x_{n+1} = x^* + \frac{1}{2} \frac{f''(x^*)}{f'(x^*)} \delta^2 + O(\delta^3) となる(\deltaの一乗の項は相殺されて消えるところがミソである)。

この性質を2次収束(quadratic convergence)という。

\deltaの「減り具合」の式からは、f(x)=0 が重根を持つような場合(f'(x^*)=0)、 ニュートン法はうまく働かないことも予想できる。

つまり、テイラー展開で \delta の3次以上の項が無視できるくらいに |\delta| が十分小さければ、1回の反復によって、誤差が \deltaの2乗に依存して、 \delta \to \frac{1}{2} \frac{f''(x^*)}{f'(x^*)} \delta^2 のように変化することになる。 このことは(感覚的には)誤差が 1/10 \to 1/100 \to 1/10000 \to \cdots と急激に減少することを意味している。


tfield-icon亀場で練習:反復写像

x の方程式 x^2/100 +x-C = 0 の解をこのページで説明した反復法で解こうと考え、y(x)=-x^2/100+C とおいた。 下図は、C=50 の場合に、xの出発値を-100とおいて反復計算を行った過程を亀場を使って表示した例である。

これと同様にして、反復を亀の軌跡によって可視化するプログラムを作成してみよ。さらに、C の値を色々と変え、亀の挙動を観察してみよ(例えばC=150)。

c-4-tfield-logistic-map