74620


MySQL の SQL 文で

[code]

    TRUNCATE(2.3, 2)
    
[/code]

とすると、本来 `2.30` が返ってくるはずなのですが、`2.29`が返されます。

`2.3` と` 4.6` の2けた切捨てに限ってそのような現象が発生するのですが、  
原因もしくはバグ報告をご存知でしたら教えてください。  
よろしくお願いいたします。

※2.3の部分は実際にはカラム名で、型はdoubleもしくはfloatになります。

**環境:**  
MySQL 5.7.26  
MAMP Mac

※実際はAWSでのサーバーですが、ローカル環境（Mac MAMP）での同様の現象になりました。


CC BY-SA 4.0
2021-03-09T05:35:33.890
74539
2021-03-12T08:11:42.033
2021-03-09T08:23:15.210
3060
44259
question
mysql
MySQL で TRUNCATE(2.3, 2) の結果が 2.30 ではなく 2.29 が返ってくる


> 2.3 と 4.6 の2けた切捨てに限ってそのような現象が発生するのですが、  
>  原因もしくはバグ報告をご存知でしたら教えてください。

### 回答

MySQLのTRUCATEの計算は2進化浮動小数点数で行われれおり、10進で表現すると桁の値が変わる現象が発生するのだと思います。  
※keitaro_soさんのコメントにある参考文献:[B.5.5.8
浮動小数点値に関する問題](https://dev.mysql.com/doc/refman/5.6/ja/problems-with-
float.html)

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


CC BY-SA 4.0
2021-03-12T08:11:42.033
74620
2021-03-12T08:11:42.033
35558
74539
answer