はじめMath! Javaでコンピュータ数学

第12回 丸め誤差と情報欠落

この記事を読むのに必要な時間:およそ 2.5 分

コンピュータの処理能力は有限です。これを最大限に活用するために仕方なく生じる誤差があります。コンピュータを使う我々は,この誤差に上手に対処する必要があります。

それはちょうど,のこぎりの刃の厚みに例えることができます。のこぎりで木を切るためには,刃の厚みが薄ければ薄いほど便利です。しかし,あまりに刃が薄いと,引くときは良いのですが押すときに刃がしなってしまいます。のこぎりの刃の厚みは,使いやすさの視点から現在の厚みに落ち着いているわけです。

道具は使いやすさのために,なにがしかの妥協を必要とする点があるものです。上手にコンピュータで計算を行うために,今回の項目をしっかり理解しておきましょう。

図12.1 道具の弱点を逆に活かすのが「技」

図12.1 道具の弱点を逆に活かすのが「技」

浮動小数点数で発生するエラーや誤差

浮動小数点数の仕組み上避けられないエラーや誤差には次に挙げるものがあります。

  • オーバーフロー/アンダーフロー
  • 桁落ち
  • 丸め誤差
  • 情報欠落
  • 打ち切り誤差

今回はこのうち「丸め誤差」「情報欠落」を学習しましょう。

丸め誤差

丸め誤差とは,丸め操作(切り上げ・切り捨て等)を行った時に入り込む誤差のことです。

丸め誤差は,演算や代入により,数値をfloat型やdouble型に格納する際に生じます※1)。

コンピュータ内部で数値は2進数で表現されているため,有効桁数の大きい数値や,無限小数になる場合など,仮数部の桁数(ビット数) で表現できない下位の部分は,IEEE754で規定されたルールに従って丸めます。当然ながら誤差が出ます※2)。

IEEE754で規定された丸めのルールには,次の4つがあります。

  • 最近値(最も近い値に丸める)Round to Nearest
  • 上向き丸め(正の無限大側の値に丸める)Round to Plus ∞
  • 下向き丸め(負の無限大側の値に丸める)Round to Minus ∞
  • 切り捨て(絶対値が小さい側の値に丸める)Round to Zero

Java 言語ではこれらのうち最近値(RN)を標準の丸め方式としています。

たとえば,0.05 は2 進数にすると,次のような循環小数になります。

  (0.00 0011 0011 0011 ...)B

float 型にこの値を格納する際には,次の二つのどちらかの値に決定しなければなりません。

V1 = (0 0111 1010 100 1100 1100 1100 1100 1100)B (0x3d4c cccc)H
V2 = (0 0111 1010 100 1100 1100 1100 1100 1101)B (0x3d4c cccd)H

真の値VPは(0x3d4c cccc ・ ・ ・)H です。VPがどちらの値に近いか減算をしてみましょう。

こうして真の値VPはV2により近いことがわかります。Java言語はこのようにして最も近い値を選択しているのです※3)。

float型は10進数にして8桁,double型で16桁程度しか有効数字がないため,高い精度を要求する計算では丸めによって生じる誤差が無視できない場合があります。例えば金銭の計算では,丸め誤差に当たる金額が,指数部の値によっては大金になります。過去には丸めで生じた金額を自分の口座に振り込み,ちりも積もれば山となる,で大金をせしめる犯罪がありました※4)。現在では金融システムでは金額の格納に実数型を用いないそうです。

※1)
丸めといって混同しやすいのは実数値を整数型変数に代入したときに起こる小数部分の欠落や,Math.round メソッドによる丸めです。これらは今回学習する丸めとは異なります。
※2)
例外として,の数列を加算して得られる10進数の小数値のみは等価な2進数に変換が可能です。例(0.625)D=(0.101)B
※3)
第8回の問題で作成したプログラムを使って,0.05の16進数表示を行い結果を確認してみましょう。
※4)
この手口は,サラミソーセージを一本丸ごと盗むとばれますが,スライスしてあるサラミソーセージのうちの一枚を盗んでも気がつかれないことに例えられ,サラミ法と呼ばれます。

著者プロフィール

平田敦(ひらたあつし)

地方都市の公立工業高等学校教諭。趣味はプログラミングと日本の端っこ踏破旅行。2010年のLotYはRuby。結城浩氏のような仕事をしたいと妄想する30代後半♂。

コメント

コメントの記入