Double型別精度問題引起的錯誤
場景說明
研發同事讓把某個double型別欄位的值四捨五入保留2位小數,mysql中round(col,2)可以實現四捨五入並且保留2位小數,但是神奇的事情發生了:發現有的四捨五入是正確的,而有的不是我們想要的結果,如下:簡單模擬此場景:
yujx>drop table dd;
yujx>create table dd (a double);
yujx>insert into dd values(956.745),(231.34243252),(321.43534),(5464.446);
yujx>select a,round(a,2) from dd;
+--------------+------------+
| a | round(a,2) |
+--------------+------------+
| 956.745 | 956.74 | #可以看到並不是我們期望的956.75
| 231.34243252 | 231.34 |
| 321.43534 | 321.44 |
| 5464.446 | 5464.45 |
+--------------+------------+
4 rows in set (0.00 sec)
如上,有的是正確的,有的不是我們期望的值,那麼問題來了,為什麼呢?
透過詢問和網上搜尋後,發現可能是因為double的精度問題導致的
查閱MySQL官當關於double、Float、DECIMAL, NUMERIC型別的介紹,如下:
FLOAT, DOUBLE
#為了說明問題,摘了官當的部分內容,關於更詳細的介紹請直接檢視官當。
12.2.3 Floating-Point Types (Approximate Value) - FLOAT, DOUBLE
#可以看到標題已經指出 Float和double是近似值
The FLOAT and DOUBLE types represent approximate numeric data values. MySQL uses four bytes for single-precision values and eight bytes for double-precision values.
Because floating-point values are approximate and not stored as exact values, attempts to treat them as exact in comparisons may lead to problems. They are also subject to platform or implementation dependencies. For more information, see Section B.5.5.8, “Problems with Floating-Point Values
因為Float、Double儲存的是一個近似值而不是確切的值,試圖使用它們儲存一個確切的值可以會導致問題。它們依賴於不同平臺和不同實現方式,而官當在章節Section B.5.5.8, “Problems with Floating-Point Values中舉例說明了此問題
參考:http://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html
“Problems with Floating-Point Values”
B.5.4.8 Problems with Floating-Point Values
Floating-point numbers sometimes cause confusion because they are approximate and not stored as exact values. A floating-point value as written in an SQL statement may not be the same as the value represented internally. Attempts to treat floating-point values as exact in comparisons may lead to problems. They are also subject to platform or implementation dependencies. The FLOAT and DOUBLE data types are subject to these issues. For DECIMALcolumns, MySQL performs operations with a precision of 65 decimal digits, which should solve most common inaccuracy problems.
由於浮點數儲存的是近似值而不是確切的值,某些時候可能導致混亂。一個浮點數值在SQL語句作為內部表示的值可能不同。試圖使用float、double來儲存確切的值可能會出現問題,他們也依賴不同平臺和實現方式。而對應DECIMAL型別,MySQL作為65位精度進行操作,可以解決此類精度問題。
如下例子證明使用Double運算遇到的異常錯誤
此結果是錯誤的,儘管前5條的a和b的值看起來是不滿足a<>b條件的。
此現象取決於各種因素,如計算機架構、編譯器版本或者最佳化級別等。例如,不同的CPU評估的浮點數不同。
如果將欄位d1和d2改成DECIMAL型別,將不會存在此問題。如下:
綜上,如果想精確的儲存浮點數值,應該使用DECIMAL.比如金額等。
DECIMAL, NUMERIC
11.2.2 Fixed-Point Types (Exact Value) - DECIMAL, NUMERIC
The DECIMAL and NUMERIC types store exact numeric data values. These types are used when it
is important to preserve exact precision, for example with monetary data. In MySQL, NUMERIC is
implemented as DECIMAL。
DECIMAL和NUMBERIC儲存的是確切的數值,使用它們可以保證精確度,例如用於儲存金額資料。在MySQL中,NUMBERIC和DECIMAL以同樣的型別實現。
double在其他平臺
double型別不只是在MySQL中存在精度錯誤的問題,在oracle、Java等平臺同樣存在此問題,如下:
簡單的0.2+0.4,但是返回的結果不是0.6。
回到問題開始
如果換成DECIMAL型別,round的結果將是正確的,如下:
yujx>drop table dd;
yujx>create table dd (a double,b decimal(30,10));
yujx> insert into dd
values(956.745,956.745),(231.34243252,231.34243252),(321.43534,321.43534),
(5464.446,5464.446);
yujx>select a,round(a,2) from dd;
綜上
只為說明一個問題,如果想要確切的儲存小數(例如,金額等),建議使用DECIMAL型別,而不是DOUBLE、float型別。
參考:
http://dev.mysql.com/doc/refman/5.7/en/fixed-point-types.html
http://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html
http://dev.mysql.com/doc/refman/5.7/en/problems-with-float.html
http://justjavac.com/codepuzzle/2012/11/11/codepuzzle-float-who-stole-your-accuracy.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/27000195/viewspace-2094689/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Double型別數值相加導致精度缺失問題型別
- Double型別轉換成BigDicimal問題型別
- Java:利用BigDecimal類巧妙處理Double型別精度丟失JavaDecimal型別
- android gson 擴充套件, 序列化int型別被轉double 問題Android套件型別
- java double、float型別的比較Java型別
- mybatis引數型別錯誤MyBatis型別
- 常見的錯誤日誌型別型別
- 記憶體拷貝引起的錯誤記憶體
- bcadd 的精度問題?
- 程式錯誤型別及其處理型別
- mysql的時區錯誤問題MySql
- MySQL主從複製錯誤——列型別轉換錯誤MySql型別
- Double BigDecimal 精度丟失總結Decimal
- 一行程式碼解決JS數字大於2^53精度錯誤的問題行程JS
- 集合 bcadd 的精度問題?
- 前端— toFixed() 的精度問題前端
- 關於Mapreduce Text型別賦值的錯誤型別賦值
- 解決 ngrok 的 Domain 錯誤問題AI
- HEAD請求方法引起方法未定義的錯誤
- 檔案格式引起的指令碼執行錯誤指令碼
- golang 指標型別引起的神奇 bugGolang指標型別
- JS大坑之19位數的Number型精度丟失問題JS
- 由分號引起的問題
- JS toFixed 精度問題JS
- 修改MySQL資料型別報 Changing columns for table XXX 錯的問題MySql資料型別
- PyTorch出現錯誤“RuntimeError: Found dtype Double but expected Float”PyTorchError
- float double 型別資料極值表示型別
- 匯入sql時報日期型別錯誤SQL型別
- Java泛型型別擦除問題Java泛型型別
- Spring Mvc Long型別精度丟失SpringMVC型別
- 自定義錯誤型別時應該注意的 nil !=nil型別
- 八皇后問題的錯誤程式碼示範
- #Java裡你還在用double作為價格的欄位型別?你犯了大錯了!Java型別
- Auth::logoutOtherDevices 導致密碼錯誤問題Godev密碼
- [Java] 浮點數的精度丟失問題與精度控制方法Java
- 深入理解 JavaScript 中的型別和型別判斷問題JavaScript型別
- org.thymeleaf.exceptions.TemplateInputException:模板錯誤報錯問題Exception
- 一個RESOURCE MANAGER引起的問題分析
- 故障分析 | show processlist 引起的效能問題