浮動小数点数の話

コンピュータは1,0の組み合わせで数を表しています。
1,0の値を取るデータの単位をビット,8ビットを1バイトといいま。
8ビット=1バイトで256通りのパターンを表すことができ,0~255の整数とみなしたり,-128~127の整数と見なしたりします。
16ビット=2バイトで65536通りのパターンを表すことができ,0~65535の整数とみなしたり,-32768~32765の整数と見なしたりします。
現在のパソコンでは32ビットが基本的で,約20億通りのパターンを表すことができますが,しょせんは有限です。
数が無限にあるという前提の数学の話はどこかで破綻が生じます。
数式処理システムといって,メモリの許す限り桁の整数を表し,
100!を正確に計算して表示するようなプログラムがあります、

例えば,Maximaなど使えば100!を以下の様に計算してくれます。

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

こういった原理的に無限に精度の高い計算は特殊な用途では必要ですが,通常のゲームプログラミングなどでは有限なデータで間に合わせます。
一方,小さい数から大きい数まで表す方法として指数表現があります。10進数だと0.123×10^3のようなものです。
なんとか×10のなんとか乗
で前の方のなんとかを仮数部,後ろの方のなんとかを指数部といいます。
仮数部は0~1未満になるように指数部を調整します。
2進数だと0.101×2^3のような感じになります。
さて,浮動小数点というからには固定小数点というのもあります。
基本的に整数なのですが,どこかに小数点があると思うものです。

浮動小数点は少ない情報で小さい数から大きい数まで表すことができますが,何せビット数,つまりは表せるパターン数が限られているので,数値の感覚が普通でないのです。10進数の場合を考えてみましょう。
0.123×10^3のように仮数部3桁,指数部1桁だとすると,指数部が0のとき絶対値で0.000から0.999までの間を1000等分,指数部が1のときのときは絶対値000から9.99までの間を1000等分ということですから,表せる数字の間隔が10倍ずつ広くなっていきます。逆に指数部がマイナスになれば間隔は10分の一ずつ小さくなっていきます。このあたり,固定小数点にすべきか浮動小数点にすべきか用途により,変わってきますが,基本的に3DCGゲームは浮動小数点で計算されることが多いです。

浮動小数点では誤差が問題になります。例えば,10進数で1/3は0.3333と無限小数になることは知っているかと思いますが,10進数の0.1は2進数では無限小数です。従って有限桁では必ず誤差が生じます。
さらに,計算すると誤差が累積することがあります。例えば,0.1を10000回足し合わせると1000より小さい値になります。それはこの0.1の2進数表現の誤差以上の大きさです。実際にfloatで試してみると大体0.1小さいです。これは大きな数字に小さな数字を足そうとすると情報が失われることに起因します。浮動小数点数は足すときに指数部を合わせます。例えば,10進数で仮数部が三桁とします。
0.101×10^0+0.100×10^1
0.101×10^0は指数部を1に合わせると0.0101×10^1ですが,もし仮数部が3桁ならば最後の一桁が失われて0.010×10^1となります。この要領で指数部に差が大きいと小さい方の仮数部をシフトする際に情報が失われます。極端な場合として0.101×10^0+0.100×10^5ならば前の小さい数は0になってしまいます。
「0.1を10000回足し合わせる」というのは何かわざとらしい例のようですが,これは,0から1まで関数1を積分する(刻み幅0.1)という場合に相当し,実は物理シミュレーションでよくある話です。足し合わせる数がどんどん大きくなって指数部をそろえるとどんどん情報が失われ,しまいには全く和に寄与しなくなります。また,このような状況で和がぴったり1000になるまで0.1を足し合わせる処理を繰り返す,というようなことをすると和が1000.0にならず,つまりは終わらない繰り返しになることがあります。

浮動小数点の表現誤差,積分などで現れる大きい数に小さい数を足すときの問題,そして値が等しいかで条件式を書く時の危うさなどわかっていただけたでしょうか?実際問題では精度はそれほど気にならないことが多く,多少問題があってもとりあえずfloatをdoubleにするだけで状況が改善されることもよくあります。しかしながら,こういった原理上の問題点に気を付けながら浮動小数点数を使うようにしましょう。

この記事が気に入ったらサポートをしてみませんか?