Excelの演算誤差

以下はおそらく2001年2月に書いたものと思われます(一番下の「追加」を除いて)。新しいExcelについてはまだテストできていません。

その1

コンピュータ内部では通常2進表現が用いられ,10進から2進への変換の際に誤差が生じる。 これが「演算誤差」と認識されることがよくある。

たとえばマイクロソフト社の [XL97] 浮動小数点数値演算の結果に含まれる丸め誤差について という文書では次のように書かれている。

Excel で、浮動小数点演算による数値計算を組み合わせた場合、その計算結果に非常に小さな誤差を含むことがあります。例えば Excel 95 で、 .5-.4-.1 を計算した場合、その結果は 2.8E-17 もしくは .000000000000000028 と評価されます。

しかし,さらに次のようにも書かれている。

注意: Excel 97 では浮動小数点演算による誤差の一部を補正する仕様に変更されて
います。上記の例を Excel 97 で計算した場合、結果は 0 になります。

実際,手許にある Excel 2000 でいろいろやってみても,2進表現に特有の誤差が出ない。 1.1 - 1 - 0.1 も 0 になるし,0.01 を 100 個加えて 1 を引いても 0 になる。 これはひょっとして BCD(2進化10進数,つまり2進の計算機での10進法のエミュレーション) を使っているのかと期待したが,そうでもなさそうである。

たとえば右の図のような計算をしてみた。 これは ε を任意の正の数としたときの (1 + ε) - 1 の最小値,いわゆる machine epsilon を求めたわけである。 BCD なら内部表現は10進であるから10進で切りのいい数が machine epsilon となるが, この計算からわかるように 2-49 = 1.776×10-15 が machine epsilon である。 明らかに内部表現は2進である。

しかし,通常の2進演算と違って,(1 + ε) - 1 の2番目に小さい数は 2-49 + 2-52 = 1.998×10-15 である。 つまり,本来の machine epsilon は IEEE 754 の double と同じ 2-52 であるが,最後の3ビットは適当に修正して10進で切りのいい数に直すという ad hoc なことをしているのであろうか。 このあたりのアルゴリズムがちゃんと公開されていないと, 恐ろしくて数値計算に使えたものではない。


その2

マイクロソフトの日本語のサイトではなく英語のサイトをサーチしてみた。 その結果,さらにおもしろいことがわかった。 XL2000: Floating-Point Arithmetic Gives Inaccurate Results によれば,Excel 2000 でも .5 - .4 - .1 は 0 になるのに 1 * (.5 - .4 - .1) は -2.78E-17 になる。 いったいどのようなアルゴリズムを使っているのであろうか。 XL2000: Floating-Point Arithmetic May Give Inaccurate Results にも例が載っている。

他にも XL2000: Solver Uses Generalized Reduced Gradient Algorithm にソルバのアルゴリズムが(簡単に)載っていた。

その3

だんだんわかってきた。 トップレベルが引き算の場合は特別なことをするようだ。 「その1」で machine epsilon を求めたときは (1 + ε) - 1 を計算したが,1 * ((1 + ε) - 1) を計算すべきだった。 改めてやってみたら, machine epsilon = 2-52 = 2.220×10-16 となり,IEEE 754 の double をそのまま使っていることがわかった。

その4

1 をかけないでも引き算全体をかっこでくくるだけで例外処理をしなくなることを教えていただいた。

追加


奥村晴彦

Last modified: 2008-10-19 08:52:29