問題描述
使用JPA
映射一個float
類型到數據庫:
然後存儲129364.57
,發現存儲的結果是129365
。
從上週就開始研究這個問題,查閱了各種資料,網上許多人都說是因爲MySQL
默認是保留六位有效數字,自己測試了一下也確實是這樣。但是查詢MYSQL
官方文檔,並沒有找到依據。
MySQL
官方文檔:Float - MySQL
如果你看到了這篇文章,歡迎評論發表意見,讓我們互相學習、進步。
結論
寫的非常好的一篇文章,MySQL
存儲的各種嘗試:MySQL數字類型int與tinyint、float與decimal如何選擇
用JPA
映射的Float
默認的長度與小數點都是0
。
這是測試的結果:float
默認能精確到6位有效數字!
原理猜想
這是MySQL
官方文檔對float
和double
的描述:
官方文檔並沒有說MySQL
是如何存儲浮點數的,所以如果沒有去讀過其源代碼,所有的博客都只是猜想。
IEEE 754
目前大多數人認爲MySQL
內部是採用IEEE 754
進行存儲的,IEEE 754 - 維基百科。
IEEE二進制浮點數算術標準(IEEE 754)是20世紀80年代以來最廣泛使用的浮點數運算標準,爲許多CPU與浮點運算器所採用。
以32
位的單精度浮點數爲例:
與日常所說的科學計數法類似。
因爲底數是有效數字,所以第一位肯定是1
,所以這個1
不進行存儲,所以雖然是23
位的底數,但是實際的底數位數其實是24
位,含有一個隱含的1
。
雙精度與此類似,一個符號位,指數位爲11
,尾數爲52
位,合計64
位。
假設
假設是用MySQL
是用IEEE 754
標準存儲的浮點數。
用單精度存儲129364.57
,其二進制爲11111100101010100.1001000111101011100001010001111011
。
正數:符號位爲0
。
指數位爲:00010000
(十進制中的16
)。
去掉第一個1
,保留23
位,底數爲:11111001010101001001000
。
所以最後的結果是11111100101010100.1001000
,轉換爲十進制爲:129364.5625
。
但是實際的MySQL
存儲後的結果爲129365
,所以猜想要麼MySQL
就是不是按IEEE 754
存儲的,要麼就是按這個存儲的但是內部爲了數據庫的性能等或其他的優化對數據進行了處理。
這裏我這裏更傾向於第二種,畢竟IEEE 754
是一種國際標準,沒有理由不遵守。