はじめに
本エントリーは某社内で実施するSQLアンチパターン勉強会向けの資料となります。
本エントリーで書籍「SQL アンチパターン」をベースに学習を進めます。書籍上でのサンプルコードはMySQLですが、本エントリーでのサンプルコードはT-SQLに置き換えて解説します。
ラウンディングエラーとは
実数を2進数でエンコードして格納する浮動小数点数のデータ型を利用すると数値に丸めが発生し、正確な数値を格納できません。また、丸めが発生した状態で連続で計算を行うことで、誤差累積が大きくなります。特に積の計算で誤差が大きくなります。
このような計算の典型が、金融システムにおける利子の複利計算になりますので、金融アプリケーションでは正確な値を使うことが極めて重要です。
有限精度・無限精度
3分の1のような有理数は0.3333…のような循環小数で表す場合、正確な値は少数では表現できません。桁数とは数の精度であり、循環小数では無限精度が必要になります。
この問題への妥協策は、可能な限りオリジナルに近い値、例えば0.333などの有限精度の値を使用することです。しかしこの妥協策は丸めの振る舞いによる誤差を生み出します。
1/3 + 1/3 + 1/3 = 1
0.333 + 0.333 + 0.333 = 0.999
アンチパターン:FLOATデータ型を使用する
SQLのFLOATデータ型は、IEEE754標準にしたがって実数を2進数形式でエンコードします。IEEE754では、浮動小数点数を2進数形式で表現します。2進数形式で無限精度が必要な値は、10進数で表現される値とは異なります。
10進数では有限精度で表せる値、例えば59.95を2進数で正確に表すには、無限精度が必要です。FLOATデータ型で無限精度は扱えないため、2進数形式で格納できる近似値を使います。その近似値を10進数形式で表すと、59.950000762939になります。
つまりデータベースのFLOAT型に格納している値は、全て有限精度で表されているとは限らず、全ての値が丸められている可能性を想定しなければなりません。
アンチパターンの見つけ方
FLOAT型,REAL型を利用しているデータベースとなります。
アンチパターンを用いてもよい場合
FLOATは、INTや、NUMERICなどのデータ型がサポートするよりも広い範囲の実数を扱う場合に適しています。
FLOATが最適なものの代表例は、科学技術計算を行なうアプリケーションです。
解決策:NUMERIC データ型を使用する
FLOATやREALなどのデータ型の代わりに、NUMERICやDECIMALを用いて、固定制度の小数点数を表すようにしましょう。
最後に
出来る限りFLOAT型は避けましょう。