勉強日記

チラ裏

SQL Antipatterns ch10 Rounding Errors

pragprog.com


Rounding Errors

Do not use FLOAT if you can avoid it.

Objective: Use Fractional Numbers Instead of Integers

  • 59.95ドルとか表現したい

Antipattern: Use FLOAT Data Type

Rouding by Necessity

  • 符号部、指数部、仮数部からなる
  • 指数部、仮数部は2進数表現
  • 10進数で有限桁で表現できる数値が、2進数では有限桁で表現できなかったりする
  • その場合、最も近い値で近似される
    • e.g. 59.95 は 59.950000762939...
  • DB製品によってはDOUBLE PRECISION型とかREAL型とかがあるが、同様の性質を有する

コラム: Meet the IEEE 754 Format

  • 科学計算分野では浮動小数点数が有用
    • 値の範囲が広いから
    • 【補】有効桁数という考え方があるから
  • お金の計算には向かない
  • Goldberg氏の資料など参照

Using FLOAT in SQL

  • DB製品によっては表示上誤差を無くしてくれたりする
  • が、データは誤差含みで格納される
  • 厳密な等価比較が成立しない
  • 誤差は蓄積する
    • 総和
    • 総乗はさらに深刻

How to Recognize the Antipattern

  • 下記データ型が利用されている場所すべてが疑われる
    • FLOAT
    • REAL
    • DOUBLE PRECISION
  • たいていのシステムではIEEE754仕様の値域を必要としない
  • アプリケーションコード側で「float」等が使われるため引きずられがちだが、より適切なデータ型がある可能性がある

Legitimate Uses of the Antipattern

  • INTEGERやNUMERICよりも広い値域が必要な場合
  • 科学計算
  • OracleのFLOAT型はScaled Numericの意
    • 他のDB製品でいうところのFLOATにあたるのはBINARY_FLOAT型

Solution: Use NUMERIC Data Type

  • NUMERIC(桁数,小数点以下桁数)
  • 依然として1/3等は正確に表現できないが、少なくとも慣れ親しんだ10進数表現にはなる
    • 59.95等を正確に格納できる