浮動小数点 条件数 とは
これまで誤差は方法から来ると思ってきました。歩幅が大きすぎる、次数が低すぎる。ところがそのすべての方法の下には、もっと根本的な限界が敷かれています。コンピュータは実数を正確に保存できません。0.1 でさえそうです。64 ビット浮動小数点は約 15〜16 桁だけ覚えて残りは丸めて捨てます。ふだんはこの微細な誤差が埋もれて見えませんが、ほぼ同じ二つの数を引いたり、小さな誤差を何百万回も積んだり、答えが入力に敏感な悪い条件数に出会うと、急に飛び出します。この講は数値解析の床、つまりコンピュータが数を扱う仕方そのものと、そこから漏れる誤差を見ます。誤差の床 (roundoff floor) がどこから来たのか、その正体です。
数直線の上の金色の目盛りが、コンピュータが正確に保存できる数です。一目で奇妙です。0 の近くは密で、右へ行くほど疎になります。浮動小数点は科学表記のように、有効数字いくつかに指数を付けて数を書くからです。だから大きさが二倍になるたびに、隣り合う表現値の間隔もぴったり二倍になります。この最小間隔を ulp(units in the last place) と呼びます。x を動かすと、大きい数ほど ulp が大きくなるのが見えます。大きい数は粗く、小さい数は細かく保存されるという意味です。すべての丸め誤差はここから始まります。
その間隔が実際どれほど小さいかを 1 の近くで測ります。ε = 2k を 1 に足しながら k をだんだん下げると、ある瞬間 1+ε がただの 1 になってしまいます。足した ε が 1 の上の表現間隔の半分より小さくなると、最も近い表現値である 1 自身へ丸められるからです。生き残っているあいだ棒は緑で、消えると赤です。金色の線がその半間隔です。この境界がマシンイプシロンで、float64 では 2⁻⁵² ≈ 2.2×10⁻¹⁶ です。約 15〜16 有効数字に当たります。これは抽象的な話ではなく本物の計算です。コンピュータにとって 1 足すごく小さい数は、ただの 1 であり得ます。精度に床があるという最初の証拠です。
誤差一つは 10⁻¹⁶ の水準なので無視してよさそうに見えます。ところが 0.1 は二進法できっかり落ちないので、保存した瞬間にすでにごく小さい誤差を含みます。それを一度足すたびに誤差も少しずついっしょに積み上がります。スライダーで足した回数を増やすと、真値 n/10 から開く誤差が着実に大きくなります。一度では見えなかったものが数百回ではっきりし、シミュレーションのように数十億回繰り返す計算では結果を台無しにし得ます。だから数値のプログラマは足す順を小さいものからに変えるか、カハン和のような補正加算でこの累積を御します。
いちばん怖いものは別にあります。ほぼ同じ二つの数を引くことです。小さい x で (1−cos x)/x² を計算してみます。真値は x が小さくなるほど 0.5 へ行くべきです。ところが素直に計算した金色の曲線は、ある瞬間 0 へ崩れます。x が小さいと cos x がほぼ 1 なので、1−cos x が有効数字をほとんど全部失うからです。先頭の桁がすべて同じで消され、信用できない末尾だけが残ります。これが壊滅的な桁落ちです。青い曲線は同じ値を 1−cos x = 2 sin²(x/2) に書き換えて計算したものです。引き算をまったくしないので 0.5 を最後まで守ります。式は同じでも、計算の順序が精度を生かしも殺しもします。
最後は誤差ではなく、問題そのものの性格です。連立方程式を解くことは二直線の交点を探すことです。金色の直線と青い直線が気持ちよく交われば交点ははっきりします。ところがほぼ平行だと、一本を髪の毛ほど揺らしても交点が遠くへ飛びます。その移動は赤い線で描かれます。スライダーで傾きを下げて二直線を平行にすると、同じ 10% の揺れで解がだんだん大きく動きます。この増幅倍率が条件数です。条件数が大きいと、入力の小さな誤差が答えで大きく膨らむ悪い条件になります。怖いのは、これが丸め誤差と違ってより良いコンピュータでも直せないことです。問題そのものが繊細だからです。だから良い数値解析は、安定なアルゴリズムと良く条件付けられた問題の両方を世話します。