矢沢 久雄

 今回は,コンピュータが数値計算を行った場合に生じる誤差の原因と対策を説明します。コンピュータの数値計算で誤差が生じるのは,仕方のないことです。コンピュータが取り扱うデータは,ビット数の限られた有限のものだからです。例えば,1÷3の結果である0.3333…という循環小数をコンピュータが正確に表すことはできません。誤差の原因は,データ形式とも密接に関係しています。誤差の原因がわかれば,計算の順序を工夫することで,誤差を少なくすることもできます。

丸め誤差

 「丸め誤差」とは,「切り捨て」や「四捨五入」によって生じる誤差のことです。例えば,正しい値が7.89であるデータを小数点以下で切り捨てれば7となり,小数点以下2けた目で四捨五入すれば7.9となり,それぞれ誤差が生じます。「誤差」とは,正しい値との差のことです。7.89と7.9の誤差は+0.01であり,7.89と7の誤差は,-0.89です。

 どのような丸め誤差が生じるかは,使用しているシステム(=ハードウエア+ソフトウエア)によってさまざまです。Visual Basicを使って作成されたプログラムで,どのような丸め誤差が生じるかを調べるために,リスト1に示した実験プログラムを実行してみました。

図1●リスト1の実行結果
 このプログラムは,(1)及び(2)のコメント(Visual Basicでは,シングル・クォーテーション以降がコメントとなります)に示した実験を行い,その結果をメッセージボックスに表示するものです。実験の結果は,(1)が8で,(2)が7.9です。小数点数を整数で表す場合でも,Format関数(書式付で数値を文字列に変換します)でも,四捨五入が行なわれることが分かりました(図1)。

 丸め誤差の原因は,コンピュータが取り扱うデータのけた数が有限だからです。けた数をはみ出したデータは,本来なら切り捨てられてしまうはずですが,Visual Basicが提供する演算子や関数が,親切機能として四捨五入を行ってくれるのです(親切機能のないプログラミング言語もあります)。丸め誤差の対策は,取り扱うデータの種類に応じて,適切なデータ表現を選択することです。例えば,7.89を8ではなく7.89のまま取り扱いたいなら,整数ではなく浮動小数点数形式の変数を使えばよいのです。

打ち切り誤差

 「打ち切り誤差」とは,特定のけたでデータが打ち切られてしまうことで生じる誤差のことです。例えば,1÷3の計算結果のような循環小数や,√2の値のような無限小数をコンピュータで取り扱おうとすると,必然的に打ち切り誤差が生じてしまいます。ここでは,リスト2に示した実験プログラムで実行してみました。

図2●リスト2の実行結果
 このプログラムは,1/3の計算結果をそれぞれ(1)単精度浮動小数点数形式,(2)倍精度浮動小数点数形式で表し,それをメッセージボックスに表示させるものです。(1)の結果は0.3333333(小数点以下7けた)となり,(2)の結果は0.333333333333333(小数点以下15けた)となりました(図2)。

 打ち切り誤差が生じる原因も,コンピュータが取り扱うデータのけた数が有限だからです。打ち切り誤差の対策は,単精度浮動小数点数形式を使って精度に問題があるなら,倍精度浮動小数点数形式を使うことです。多くのプログラミング言語では,倍精度浮動小数点数形式が,最大のデータ型なので,これでも精度が足りないなら,単独のデータで表すことは不可能です。

情報落ち

 「情報落ち」は,浮動小数点数の計算において生じる誤差です。リスト3は,1.23と4.56×1018の足し算の結果をメッセージボックスに表示する実験プログラムです。4.56E+18は,Visual Basicで4.56×1018を表記する書式です。

図3●リスト3の実行結果
 1.23+4.56×1018=1.23+4560000000000000000=4560000000000000001.23となるはずです。ところが,プログラムの実行結果として表示される値は,4.56E+18すなわち4.56×1018であり,1.23が足されていません。1.23が消えてしまったのです。これが,情報落ちです(図3)。

 情報落ちの原因は,浮動小数点数形式の2つのデータの計算が,指数部を大きい方に揃えてから行なわれるからです(浮動小数点数形式のデータ表現に関しては,この講座の第3回を参照してください)。いかにコンピュータといえども,指数部の異なる2つのデータをそのまま足すことはできません。皆さんも,2×102+3×103という計算をする場合,2×102+30×102=32×102もしくは0.2×103+3×103=3.2×103のように,指数部を揃えて行うでしょう。

 コンピュータは,1.23+4.56×1018という計算を,0.0000000000000000123×1018+4.56×1018=4.5600000000000000123×1018として行います。ここでは,仮数部が52ビットの倍精度浮動小数点数を使っているので,4.5600000000000000123×1018の下線部までしか仮数部を持つことができず,それ以下の数値は切り捨てられてしまいます。これによって,00123という情報が消えてしまったのです。

 情報落ちは,浮動小数点数形式で表された小さな値と大きな値の計算を行う場合に生じます。対策としては,もしも「大きな値」+「中くらいの値」+「小さな値」という3つのデータの計算を行うなら,計算の順序を(「小さな値」+「中くらいの値」)+「大きな値」として,大きさの近いデータの計算を先に行うようにします。ただし,実験プログラムのような「小さな値」+「大きな値」という2つのデータの計算では,対策の施しようがありません。

けた落ち

 浮動小数点数の計算において生じる誤差には,「けた落ち」というものもあります。けた落ちは,絶対値がほぼ等しい2数の減算によって生じます。リスト4は,1.234E+18-1.232E+18の計算結果をメッセージボックスに表示する実験プログラムです。

図4●リスト4の実行結果
 プログラムの実行結果として,メッセージボックスには2E+15と表示されます(図4)。この計算結果は,正しいものです。ただし,厳しいことを言えば,計算結果は0.002E+18が正解です。なぜなら,もとの計算の有効けた数(仮数部のことだと考えてください)が4けただったので,計算結果の有効けた数も4けたとなるべきだからです。2E+15では,有効けた数が1けたになっています。これが,けた落ちです。科学計算の世界では,有効けた数を揃えるということが厳しく要求されます。例えば,2と2.000は意味が異なるのです。

 けた落ちの原因は,浮動小数点数形式のデータの仮数部が正規化されるからです。0.002E+18を正規化したものが2E+15です(実際には,2進数で正規化が行なわれますが,ここでは10進数でイメージをつかんでください)。けた落ちの対策は,3つ以上の数値の計算なら計算の順序を工夫して,けた落ちが生じないようにすることです。2つのデータの計算では,基本的に対策の施しようがありませんが,計算式を3つ以上のデータの計算に変形してけた落ちを防ぐというトリッキーな方法もあります。

 金銭計算のデータのように,1円の過不足もなくピッタリと帳尻を合わせなければならない場合には,誤差が許されません。ただし,物の長さや質量などのデータを取り扱う場合には,わずかな誤差は問題になりません。正しくは1mであるものが,0.999mで処理されても困らないでしょう。いずれにしても,正確無比のように思えるコンピュータにも誤差が付き物であることと,データ表現や計算方法を工夫すれば誤差を少なくできる可能性があることをおぼえておいてください。誤差と上手に付き合いましょう。

 この講座をお読みいただき,ありがとうございました。皆さんのご健闘をお祈り申し上げます!