fc2ブログ

makopi23のブログ

makopi23が日々の生活で感じたことを気ままに綴るブログです。

SQLアンチパターン読書会 「ラウンディングエラー」 に参加しました

2013/9/24(火) SQLアンチパターン読書会 「ラウンディングエラー」に参加してきました。

DoorKeeper
http://sqlap.doorkeeper.jp/events/5668

以下の書籍をターゲットとした読書会なのです。
SQLアンチパターンSQLアンチパターン
(2013/01/26)
Bill Karwin

商品詳細を見る


場所はいつもの湯島、株式会社アルティネットさんです。
いつも会場提供ありがとうございます。

参加者は12人かな。けっこう会議室のキャパ、ギリギリです。
この勉強会、もうすっかり全員、顔見知り。
毎度、出席率がほぼ100%な勉強会も珍しい。それだけ充実しているということですね。



■アジェンダ
今回は中澤さんがアジェンダを作成して説明してくださいました。感謝!

SQLアンチパターン読書会 09章 ラウンディングエラー from Yosuke Nakazawa

各RDBMSの小数点型の調査など、独自に纏めてくださっているのが良いですね。

あと、@akuraru さんも2進数演算について説明するスライドを作ってきて説明してくださいました。
こーゆう自発的なのは良いですね~

以下、個人メモ。


■ディスカッション

いつものように、ディスカッションしたいネタを各自、付箋に書き出して模造紙に貼りました。
20130924_sqlap_1.jpg

■ラウンディングエラーが原因による事故

今回衝撃的だったのは、ラウンディングエラーが原因で多数の命を失った事故事例の話でした。

●パトリオットミサイルの防御失敗
http://www.sydrose.com/case100/298/

湾岸戦争時に、ラウンディングエラーによる誤差によりミサイル撃墜に失敗、28名が死亡し100名近くが負傷したとのこと。
これは恐ろしいですね。。。

あと、小数点がらみでロケットが爆発した事故とか。

●アリアン5型ロケット爆発事故
http://www.sydrose.com/case100/284/

64ビットの浮動小数点数から16ビットの整数暗号に変換する過程で変換に失敗し、これが原因でロケットが爆発したとのこと。

あと 通称「きのこ本」のP.124あたりにも、これ関連の話が掲載されています。@t_wada さんに紹介いただきました。
プログラマが知るべき97のことプログラマが知るべき97のこと
(2010/12/18)
和田 卓人、 他

商品詳細を見る


エンジニアのミスが人命に関わるというシビアな話で、いきなり身が引き締まる思いである!

■小数の表現方法

・基本的に、DBに「小数」を持たせないように設計する。
 (案1)DBには「計算式」を文字列で持たせておき、必要な時まで計算しないようにする。
 (案2)DBには「整数」で値を持たせておく。そのため、単位変換を行う。
    (例1)"0.5時間"という持たせ方ではなく、"30分"というように単位変換して整数にする。
    (例2)消費税を持たせる場合は"1.05"ではなく、"5"と整数で持たせる。

・DBのカラム名には単位を入れましょう、という話は昔よくあったらしい。

・小数を使わない、というのはアプリケーションの設計ではありえる。
 例えば、センチメートルではなくミリメートルで扱うようにしましょう、とか。

・上記(案2)でデータを「整数」で持たす場合は、画面への表示時に小数に変換する。
 → 単位変換ライブラリを使う、あるいはストアドプロシージャで変換することもある。
 → どちらが良いかは場合による。
   ①ストアドで変換した方が性能が良いことがある。
   ②DBにいくつシステムが繋がっているかによって、どちらに計算させるかは変わる。

・金融業界だと、銀行の合併でシステム統合する際、データの持たせ方が互いに異なり、困ることがある。
 → マテリアライズドビューを使うのが選択肢の1つ。


■DBMSやプログラミング言語の差異
・リテラルで書いた値が処理系によってどう解釈されるかが問題になる。
 例えばPostgreSQLだと、SQLの比較演算の右辺に59.95と書くと、Numericとして判定される。
 でもPostgreSQLのDB側は値をFloatで持つので、比較すると一致しないという事象が生じる。

・MySQLは、バージョン5.1より前はDecimalでも丸め誤差が生じるらしい。
 5.1より前は、保存は10進数、計算は2進数だったらしい。
 5.6.4より前はマイクロ秒が扱えなかったらしい。

・Oracleは10進数表現のNumber型がデフォルト。そもそもFloatでさえ10進数で扱われるらしい。
・MySQLのNumericは64桁まで扱えるらしい。
・PostgreSQLのNumericは、バージョン9までは1000桁で、バージョン9.1以降は1000桁以上扱えるらしい。

・Javaだと、金額にはFloatではなくBigDecimalを使え、というのは暗黙の了解。
・C言語はDecimalに対応する型がない。
・Groovyはデフォルトで小数をBigDecimalで扱うらしい。
・PHPはビルドオプションを指定しないとDecimalが扱えないらしい。
・PHPはオーバーフローするとIntからFloatに勝手に切り替わるので怖すぎる。。。
・PHPは型がないので、DBにFloatで入っている値を取り出すときに絶望的になる。。。
 → なのでドライバの段階で文字列として取り出して、そこで必要な桁数だけシフトしてデータを残したりして対処したりする。
・Javascriptは倍精度浮動小数点がデフォルト。
・COBOLは金額処理が多いのでDecimalの概念に馴染み深い。逆にFortranだと科学技術計算が多いのでFloatやDoubleに馴染み深い。


■ラウンディングエラーに関するお勧めブログエントリ
@t_wada さんオススメ、iakioさんのエントリ。



■Float/DoubleでDBに入った値をどうするか問題
・これが一番辛い。。。
・まず、DBから一度「文字列」で取り出す。
・その後、文字列からDecimalに変換する。でも移行が辛い。。。


■FloatとDecimalの性能差
・FloatよりDecimalの方が性能は(数倍?)悪い。



★感想:
今回のラウンディングエラー、FloatじゃなくNumeric使え!というオチで、ある意味単純で話が膨らむかなぁ、と思っていたんですが、予想に反して話題がとても多く驚きでした。
いやぁ、自分の知らないことは多いもんだ。。。

あと、そもそもDBでFloatを使ったことがない、という方も何名かいらっしゃいました。
DB上では整数で値を持たせる設計にする、という話は私にとって斬新でした。

ちなみにこの章を読んでて、FloatやDoubleの仕組みや2進数計算、みんな当たり前のように理解しているのだろうか?という疑問が沸きました。
ちなみに私、大学は情報工学専攻だったので、このへんは徹底的にブチ込まれたクチです。
なのでラウンディングエラーなんてこの業界、当たり前じゃん!という思いで読んでたんですが、もしかして、当たり前じゃないと受け取るエンジニアは案外多いのだろうか・・・とか疑ったり。

そして、そーゆうエンジニアが人命に関わるシステムを設計してるとなると・・・恐ろしや。

あと小数の扱い自体が、DBMSやプログラミング言語の差異により結構あるなぁ、というのが感想です。
ここはかなり注意する必要がありそうです。

参加者の皆様、ありがとうございました。

-->