浮動小数点数の話 2013年度版

8,440 views
8,286 views

Published on

第70回PHP勉強会の発表資料です。

Published in: Technology
0 Comments
16 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
8,440
On SlideShare
0
From Embeds
0
Number of Embeds
4,368
Actions
Shares
0
Downloads
16
Comments
0
Likes
16
Embeds 0
No embeds

No notes for slide

浮動小数点数の話 2013年度版

  1. 1. 浮動小数点数の話 2013年度版 hnw 第70回PHP勉強会(2013/07/22) 発表資料 13年7月23日火曜日
  2. 2. 自己紹介 @hnw / id:hnw 勤務先:KLab株式会社 カレーとバグが大好物 最近の興味:Zend OPcache 改造しがいがある、最近イチオシのオモチャ 13年7月23日火曜日
  3. 3. 今日おはなしすること 浮動小数点数の怖い話 round関数の近況 MySQLでの小数の扱い 13年7月23日火曜日
  4. 4. 浮動小数点数の怖い話 round関数の近況 MySQLでの小数の扱い 13年7月23日火曜日
  5. 5. 浮動小数点数の怖い話(1) 例:ゲーム内のアイテムの売買機能 プレイヤーはアイテムを店で定価で買える 定価の10%増しで、NPCが買い取ってくれる 端数が出た場合、小数点以下切り上げ(5.5→6) 13年7月23日火曜日
  6. 6. 浮動小数点数の怖い話(1) 例:ゲーム内のアイテムの売買機能 プレイヤーはアイテムを店で定価で買える 定価の10%増しで、NPCが買い取ってくれる 端数が出た場合、小数点以下切り上げ(5.5→6) 罠に気づきましたか? 13年7月23日火曜日
  7. 7. 浮動小数点数の怖い話(2) 定価100コインのアイテムの売価が111コインになる! 100の10%増しなら110 のはずでは…? 実験してみる(1.1倍して切り上げ) 13年7月23日火曜日
  8. 8. 何が問題だったか? 1.1倍したのが問題 1.0や0.5はピッタリ表現できるが、0.1だと誤差が入る 11.0倍して10.0で割っていれば問題なかった 13年7月23日火曜日
  9. 9. 補足(1) 浮動小数点数の性質からくる問題 浮動小数点数は2進数なので、1/5は循環小数になる 有限桁(53bit)で打ち切られるので、誤差が入る PHPに限らず、多くの言語で起こる現象 10進小数クラスや有理数クラスを持つ言語もある 13年7月23日火曜日
  10. 10. 補足(2) 浮動小数点数演算で誤差を避ける方法は? 浮動小数点数で「ピッタリ」表せる数を使うこと 誤差が入りうる計算を後回しにすること 整数演算だけで済む仕様に誘導するのも手 13年7月23日火曜日
  11. 11. 補足(3) 浮動小数点数で無理ならgmp関数を使ってもよい BC Mathは素性が不明だわ遅いわでイマイチな印象 「その処理をPHPでやるのが正解か?」も要検討 13年7月23日火曜日
  12. 12. 浮動小数点数の怖い話 round関数の近況 MySQLでの小数の扱い 13年7月23日火曜日
  13. 13. こんなことがありました PHP 5.2.xのround関数の実装がイマイチというネタで炎上 http://d.hatena.ne.jp/hnw/20070515 日記書き始めて10エントリ目くらいだった まつもとゆきひろさんの日記で言及→DIS大会 13年7月23日火曜日
  14. 14. 応戦してた どう見てもヤバい人です。 13年7月23日火曜日
  15. 15. 当時のround関数の概要 round(x)の実装が普通と違った 普通の実装:x > 0 なら floor(x+0.5) PHPの実装:x > 0 なら floor(x+0.50000000001) 13年7月23日火曜日
  16. 16. 当時のround関数の概要 round(x)の実装が普通と違った 普通の実装:x > 0 なら floor(x+0.5) PHPの実装:x > 0 なら floor(x+0.50000000001) ↑ 意味わからん 13年7月23日火曜日
  17. 17. 議論の概要 PHP以外の人「これだからPHPは」 僕「指摘が浮動小数点数的に間違ってるけど?」  「RubyやPythonやPerlのコレもバグじゃね?」 浮動小数点数まわりのバグが結構見つかった PHPがひどい点については基本スルー 13年7月23日火曜日
  18. 18. 今どうなってるか(1) PHP 5.3以降、round関数の仕様と実装が変わりました 詳細:https://wiki.php.net/rfc/rounding x > 0 なら floor(x+0.5) と、他の言語と同様の実装 大きい数にだけ起こる、直しにくいバグが残っている http://d.hatena.ne.jp/hnw/20110407 13年7月23日火曜日
  19. 19. 今どうなってるか(2) 僕が当時指摘したバグはRuby 1.8.7とPython 2.7.3で すべて修正されている すげえ! なおPerl 5.14.4では修正されていない模様 13年7月23日火曜日
  20. 20. 浮動小数点数の怖い話 round関数の近況 MySQLでの小数の扱い 13年7月23日火曜日
  21. 21. MySQLでの小数 小数リテラルは固定小数点数になる 固定小数点数=桁数と小数点の位置が決まっている表現 MySQLではDECIMAL型が対応する DECIMAL(10, 2) : 全10桁、小数以下2桁 13年7月23日火曜日
  22. 22. 固定小数点数の世界 誤差の問題から解放される これで平和が訪れた! = true 13年7月23日火曜日
  23. 23. 固定小数点数の世界 誤差の問題から解放される これで平和が訪れた! と思ったでしょ?残念! = true 13年7月23日火曜日
  24. 24. 浮動小数点数の恐怖再び 文字列リテラルに対して加減算→自動キャスト 文字列を数値にキャスト→浮動小数点数になる = false 13年7月23日火曜日
  25. 25. イマイチなPDOの仕様 PDOはプレースホルダの展開時に PHP変数の型が文字列なら必ずクォーティングする PDO::PARAM_INTの指定はbool型のみ影響する 参照:http://stackoverflow.com/questions/833510/ php-pdobindparam-data-types-how-does-it-work 数値なのに文字列型になっている場合は要注意 13年7月23日火曜日
  26. 26. 小数を避ければ平気か 「DB上で小数なんて使わないから自分には関係ない」 とか思ってませんか 小数点が無くても浮動小数点数を経由します = true 13年7月23日火曜日
  27. 27. 何が起きたのか? 文字列をキャストして浮動小数点数になった 2^53以上の整数は浮動小数点数で正しく表現できない 前のページの例では、1を足したはずが2増えた 10進で16桁以上の整数を扱う場合は要注意 BIGINT型など 13年7月23日火曜日
  28. 28. まとめ 浮動小数点数は罠がたくさん 罠を避けるには知識が必要 PHPのround関数は昔よりマトモになった MySQLにも浮動小数点数の罠がある PHPだとPDOがイマイチなせいで罠を踏みやすい 13年7月23日火曜日
  29. 29. ご静聴 ありがとう ございました 13年7月23日火曜日

×