リニア・テック

ログイン

カート

ホーム理論メモ「解析的」と「数値的」

「解析的」と「数値的」

インデックス

方程式を解く,微分する,積分するといった計算をするとき,大きく分けて「解析的に解く」と「数値的に解く」という2種類のアプローチが考えられます.ここでは,簡単な具体例を使ってこれらの違いを解説します.

解析的

「解析的」(analytical)とは,数式の変形のみによって最終的な答えを導くことを指します.いわゆる「ペンと紙を使った手計算」がこれに該当します.(ただし,後述のとおり人間が手計算で「数値的」な解法を実行することもできるので,「ペンと紙を使っていれば解析的だ」とは言い切れません.)

解析的に得られる結果は,その計算過程によらず一意に定まります.また計算結果は厳密な値であり,そこに誤差は含まれません.このあたりの話は,実際に次の具体例を見たほうがわかりやすいと思います.

方程式を「解析的」に解く例

簡単な例として,中学校で習う次の方程式を解いてみます.

$2x+1 \ =\ 0$

左辺の $1$ を右辺に移項し,さらに両辺を $2$ で割れば方程式の解 “$x$” が得られます.

$x \ =\ -\cfrac{1}{2}$

このように,式変形だけで方程式の解を得る操作を「解析的」な解き方といいます.なお,式を変形する手順は他にも考えられます.たとえば最初に「両辺を $2$ で割る」など,いくらでも自由度があります.それでも,最終的な結果は “$x=-1/2$” という値に一意に定まります.当然だと思われるかもしれませんが,これは解析的な計算の重要な性質です.また,この “$-1/2$” という値には一切の誤差が含まれません.あくまでも純粋な “$-1/2$” です(たとえば “$-0.5000001$” などにはならない).

さて,“$a$” と “$b$” を定数として次の方程式を考えます.

$ax + b \ =\ 0$

上式を「解析的」に解くと,次のようになります.

$x \ = \ -\cfrac{b}{a}$

上式は,あらゆる “$a$” と “$b$” の値(ただし “$a\neq 0$” とする)に対応した「一般的な解の表現」となっています.実際,上式に “$a=2$”,“$b=1$” を代入すれば先ほど考えた方程式 “$2x+1=0$” の解が得られます.このように,定数を文字として残したまま一般解を表現できるのも「解析的」な計算方法の強みです.

数値的

「数値的」(numerical)とは,特定の計算手順(これを「アルゴリズム」という)にしたがい,具体的な数値に対する計算を繰り返して最終的な結果を得ることを指します.

一般的な数値計算のアルゴリズムには,何らかの「繰り返し処理」が含まれます.特に「反復型」と呼ばれるアルゴリズムでは,繰り返し回数が多いほど計算結果が正しい値(真の解)に近づきます.ただし,繰り返し回数を増やすとその分だけ計算時間が長くなるので,精度と時間の間にはトレードオフがあります.現実的には有限の繰り返し回数で計算を停止するので,数値的な計算結果には必ず何らかの「誤差」があります.

方程式を「数値的」に解く例

ここでは,「2分法」(bisection method)という単純なアルゴリズムで方程式 “$f(x)=0$” を「数値的」に解く方法を紹介します.

  1. “$f(a)\cdot f(b) < 0$” を満たすように,適当な始点 “$a$” と 終点 “$b$” を設定する.
  2. 対象の区間を2等分する点 “$c = \cfrac{a+b}{2}$” を求める.
  3. “$f(a)\cdot f(c) < 0$” なら “$b$” に “$c$” を上書きする.そうでなければ “$a$” に “$c$” を上書きする.
  4. 上記の「手順2」と「手順3」を繰り返す.

[手順1] 最初の “$f(a)\cdot f(b) < 0$” が成り立つ状況とは,上図のようなイメージになります.このとき “$y= f(x)$” のグラフは “$y=0$” のライン($x$軸)と交差するので ,“$f(x)=0$” が成り立つ点 “$x$”(これが方程式の解になる)は “$a$” と “$b$” の間に必ず存在します.

[手順2] ここで,“$a$” と “$b$” の中点 “$c=(a+b)/2$” を計算します.

[手順3] もし “$f(a)\cdot f(c) < 0$” なら,解 “$x$” は「“$a$” と “$c$” の間にある」はずなので,もとの “$b$” に “$c$” の値を上書きして対象範囲を狭めます.そうでなければ,解 “$x$” は「“$a$” と “$c$” の間にはない」つまり「“$c$” と “$b$” の間にある」はずなので,もとの “$a$” に “$c$” の値を上書きします.

[手順4] こうして得られた新しい “$a$” と “$b$” に対して,再び [手順2] の式で中点 “$c$” を計算し,[手順3] にしたがって “$a$” と “$b$” を更新します.これを繰り返せば,中点 “$c$” の値が真の解 “$x$” に限りなく近づいていきます.実際に上図で各ステップにおける中点の動きを追うと,“$c_1 \to c_2 \to c_3$” と移動するにつれて「解」に近づいていることがわかります.

なお,解が存在する区間の幅 “$b-a$” は計算結果の「誤差」に相当します.通常は,この “$b-a$” が設定値(いわゆる「しきい値」)よりも小さくなったところで計算を終了します.

一般に,コンピュータは単純な計算処理を高速で繰り返すのが得意です.そこで,今回はPythonでプログラムを書いてコンピュータ上で「2分法」を実行してみます.解く方程式は先ほどと同じ “$2x+1=0$” です.なお,Pythonの実行環境については Pythonインタプリタのインストール を参照してください.

#=============================
#function: f(x)
def f(x):
	return 2*x + 1
#=============================
#bisection method
a = -10
b = 10
epsilon = 1e-5
count = 0
while(True):
	c = (a+b) / 2
	print("loop[%d] c = %.8f" % (count, c))
	count += 1
	if f(a) * f(c) < 0:
		b = c
	else:
		a = c
	if b-a < epsilon:
		break
print("==============================")
print("solution: %.6f" % c)

[1行目 - 4行目] “$f(x)=2x+1$” を計算する関数 “f()” を定義しています.

[5行目 - 10行目] 今回は2分法の初期値を “$a=-10$”,“$b=10$” としました.実際 “$f(-10)\cdot f(10) = -399 < 0$” となるので,初期条件としては妥当です.変数 “epsilon”(イプシロン)は解の精度を設定するために使います.今回は $1\times 10^{-5}$ としました.“count” はループ回数をカウントするための変数で,2分法の本処理とは無関係です.

[11行目 - 20行目] 2分法のメイン・ループです.新しい中点 “c” を計算して “a” と “b” の値を更新し,“(b-a) < epsilon” が成立したところで計算を終了します.また,ループごとにその時点の繰り返し回数を表示します.

[21行目 - 22行目] 最終的な計算結果を小数点以下6桁まで表示します.

このプログラムを実行すると,次のような結果が表示されます.

今回の計算結果の $-0.500002$ は,同じ方程式を「解析的」に解いた結果である $-1/2$ と整合します.今回は許容誤差 “epsilon” の値を $1\times 10^{-5}$ に設定したので,小数第5位までの $-0.50000$ は真の解 $-1/2$ と一致します.しかし,小数第6位は $2$ であり誤差が生じていることがわかります.変数 “epsilon” の値によって誤差の大きさは変わりますが,本質的に何らかの誤差が生じることは変わりません.そういった意味で,コンピュータによる数値計算の結果はあくまで「近似解」だと見なすべきです.

また,原理的には「2分法」のアルゴリズムを人間の手計算で実行することも可能です.人間が計算する場合でも,有限の繰り返し回数で計算を打ち切れば必ず誤差が生じます.さらに,コンピュータ上で数値データを扱うときは有限の桁数しか表現できないので,いわゆる「丸め誤差」が発生します.よって,今回のプログラムによる計算結果には「有限の繰り返し回数による誤差」と「有限の桁数による丸め誤差」の両方が含まれていることになります.

「解析的」と「数値的」の使い分け

実際のところ,「解析的に解ける問題」というのは全体のごく一部です.たとえば,2次方程式 “$ax^2+bx+c=0$” には「解の公式」があるので解析的に解けます.さらに,3次方程式や4次方程式にも解の公式があります.しかし「5次以上の$n$次方程式には解の公式が存在しない」ことが証明されており,解析的には解けません.(なお,任意の$n$次方程式には$n$個の解があることが「代数学の基本定理」として証明されています.よって,5次以上の方程式は「本質的には解がある」が「その解を解析的に求める方法がない」という話になります.)

これに対してコンピュータによる数値計算は,アルゴリズムが通用する範囲ならば何らかの計算結果を(強引に)出すことができます.たとえば「ニュートン法」などのアルゴリズムを使えば,5次以上の$n$次方程式であっても原理的には解くことができます.有限の繰り返し回数で計算を打ち切った場合の結果はあくまで近似解ですが,誤差が十分に小さければ実用上問題なく利用できます.そのため,数値計算は研究・開発の現場で非常に大きな役割を担っています.

一般に,数値計算を実行して解を得るためのソフトウェアを「シミュレータ」(simulator)といいます.特に,方程式や微分方程式を解くためのプログラムは「ソルバ」(solver)と呼ばれます.材料,化学,機械,電気,制御,建築といった様々な分野に特化したシミュレータやソルバが数多く開発・販売されています.

なお,電磁気学 のセミナでは電場や磁場を数値的に計算するプログラム(簡単なシミュレータ)を実際に作り,解析的な計算によって得られた結果と比較するという実験を行います.

数値計算は強力ですが,使いこなすのが難しい面もあります.たとえば同じ計算対象でも,初期条件によって結果が変わってしまうことがあります.先ほど作った「2分法」のプログラムでも,変数 "a" と "b" の値を変えると計算結果が変わります.また,2分法ではない別の「方程式を解くアルゴリズム」を採用すれば,それに伴い計算時間や誤差などが変化します.1つの問題を解くためのアルゴリズムが何種類も考案されていることもあるので,そういった場合は状況に合わせて最適なアルゴリズムを選択する必要があります.

同じアルゴリズムを使う場合でも,ソース・コードの書き方によって計算結果が変わることがあります.特に,各計算ステップにおける誤差の取り扱いは重要です.意識してコーディングしないと,まったく使い物にならないプログラムになってしまうことも珍しくありません.また,数学的な処理をまとめたライブラリは便利ですが,正しい使い方を理解せずに乱用するとおかしな計算結果に振り回されることになります.

「解析的」な計算は式変形だけで結果を導くので,原理的に「途中で誤差が混入する」ということがありません.近似計算をするとしても,通常は近似による誤差の程度を定量的に把握できます.「解析的」な計算方法を習得するにはそれなりの訓練が必要ですが,「数値的」な計算でよく見かける「事故」は起きにくいので,トータルで見れば安全・安心な計算方法であるとも言えます(計算ミスをしなければの話ですが).

また先ほど触れたとおり,「解析的」な計算では定数を文字のまま残した「一般解」を表現することができます.「数値的」な計算では常に具体的な数値しか扱えないので,どうしても視野が狭くなりがちです.対象の一般的な性質に関する理論的な考察をしたいなら,「解析的」な計算が必要不可欠です.結局,「具体的な数値解」と「抽象的な解析解」の両方を使いこなすことが研究・開発の仕事を効率良く進める上で重要となります.