数値計算が必要になる簡単な例として、二次方程式をとりあげてみよう。 たとえば、
A2 + B2 = C2(A: 底辺の長さ; B: 高さ; C: 斜辺の長さ)を使えばよいが、 このうちひとつ、たとえばBが未知だとすれば、これは一種の二次方程式 になる。
Q1 ・ (x - x1)-2 = Q2 ・ (x - x2)-2これは(-2)乗を含んでいるので2次方程式ではないが、近似・変形すれば2次方程式 に持ちこめるのではないだろうか(未確認)。
二次方程式については、解の公式がある。代数方程式(「xの多項式 = 0」 の形)のうち4次までのものについて公式が知られている。 それより高い次数のものについては、直接解を求める式はなく、 数値計算の問題としては、有限桁数での近似解を求める方法がいろいろと くふうされている。
二次方程式
a x2 + b x + c = 0の解は、
- b + sqrt ( b2 - 4 a c ) - --------------------------- 2 aである。ただし、+ と - が上下に書いてあるところは、両方の解がある ことを示し、sqrtは平方根を表わす。
a, b, cを読みこんで、2つの解を計算するプログラムを書いてみよう。 まずは、公式をすなおにプログラム化すればよい。 実数の平方根を計算する関数は、Pascal, Fortran, Cのいずれでも sqrt である。(一部のBASICではsqrというが、Pascalのsqrは2乗を計算するので 区別に注意すること。Fortranではbの2乗は b**2 と書く。) 例文は nizi2.p, nizi2.f, nizi2.c にある。 ここでは(わざと)単精度を使っているが、実用には倍精度のほうがよい。
なお、 nizi.p, nizi.f, nizi.c も同じ計算だが、 もしこれをコンパイラがすなおに機械語に翻訳したとすると、 平方根の計算を2回することになるので、 nizi2.{p,f,c}よりも実行効率が悪い。 しかし、多くのコンパイラには、これを1回ですませるように 「最適化」するオプションがある。それを使うとすれば、 nizi.{p,f,c}のほうが単純なだけよいプログラムということになる。
この例文は結果が実数になる場合だけを想定している。つまり 引き数(かっこの中)が正または0でないと、動作しない(エラーメッセージ を出して、止まるかまたは無意味な結果を出すはずである)。したがって、 解が複素数になる場合までカバーしようとすれば、b2 - 4 a c の値 によって場合分け(if文による条件分岐)をしなければならない。
Fortranでは複素数型を使うこともできるが、ここではそうしても 特に便利にならないので、実数型(倍精度を含む)でやってみてほしい。
直角三角形の2辺からもう1辺を求める問題は、この公式を使っても よいが、もっと簡単にできるので考えてみてほしい。
公式をそのままプログラム化したものは、仮に計算機の実数型の 有効数字が無限にあれば、正しい結果を出すはずだが、実際には有限 であるために、誤差が生じる。これをまるめ誤差という。
数値計算法の古典的教科書の著者でもあるフォーサイス (G. E. Forsythe)先生が、計算をするときはこの誤差を考慮して 計算手順(アルゴリズム)を考えなければならないことを、二次方程式を例に 述べている。詳しくは本を見てほしい。
この解説では、10進法8桁の浮動小数点表現を持ち、 指数の範囲は絶対値30までであるような計算機を想定している。 まず、さきに述べた公式をすなおにプログラム化してみる。
浮動小数点のまるめ誤差の問題はいろいろなところで顔を出すが、 特に、「よく似た数値の引き算」 (あるいは、絶対値が近くて符号が反対の数のたし算)をすると 精度が落ちる。「桁落ち」というのはふつう、このことである。 たとえば、
1.0000001 -) 1.0000000 ------------ 0.0000001という例を考えてみると、もとの2つの数には有効数字が8桁あっても、 結果には1桁しかない。形式的に 1.0000000e-7 と書いたとしても、 最初の1以外の7桁は「無効数字」にすぎない。 数値計算をするときは、このような「桁落ち」をさけるアルゴリズム を使うことが望ましい。
現実には実数の式通りにプログラムする ことが多いが、倍精度を使い、さらに結果のわかった問題で テストしてみて、おかしいと思ったら桁落ちが おきそうなところをチェックすることを勧める。
必ずしも完全ではないが、多くの場合に実用的な形にした 2次方程式を解くプログラムを nizi3.p, nizi3.f, nizi3.c に用意した。
次の点を考慮したものである。