質問: MySQL の SQL 文で ``` TRUNCATE(2.3, 2) ``` とすると、本来 `2.30` が返ってくるはずなのですが、`2.29`が返されます。 `2.3` と `4.6` の2けた切捨てに限ってそのような現象が発生するのですが、 原因もしくはバグ報告をご存知でしたら教えてください。 よろしくお願いいたします。 ※2.3の部分は実際にはカラム名で、型はdoubleもしくはfloatになります。 **環境:** MySQL 5.7.26 MAMP Mac ※実際はAWSでのサーバーですが、ローカル環境(Mac MAMP)での同様の現象になりました。
回答: > > 2.3 と 4.6 の2けた切捨てに限ってそのような現象が発生するのですが、 > > 原因もしくはバグ報告をご存知でしたら教えてください。 > > > ### 回答 MySQLのTRUCATEの計算は2進化浮動小数点数で行われれおり、10進で表現すると桁の値が変わる現象が発生するのだと思います。 ※keitaro_soさんのコメントにある参考文献:B.5.5.8 浮動小数点値に関する問題 MySQL固有の問題ではなく、2進化浮動小数点数で計算するときは同じ現象が発生します。 ### 確認した内容 十進形式の浮動小数点数2.3は二進形式で表現すると循環小数になります。 10進数2.3を2進数で表現すると10.010011001...(1001が循環) ですが、正規化すると1.0010011001...(1001が循環)×2の1乗となります。 floatの小数部が23bitだとすると、10進数2.3は2進数で1.00100110011001100110011×2の1乗で、これを10進数に変換すると2.299999952となり、結果は2.3より小さくなります。 MySQLは10進数2.3を文字列で管理しているが(推測です)、計算は2進化浮動小数点数2.299999952で行うため今回のケースが発生するのだと思います。 2の累乗倍は指数部が変わるだけなので、2.3×2の累乗倍でも同じ現象が発生すると考え、9.2、1.15で確認したところ、2.3や4.6と同様の現象が確認できました。 ### 確認に使用したMySQLのバージョン mysql Ver 15.1 Distrib 10.5.9-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2