您好,登錄后才能下訂單哦!
研發(fā)同事讓把某個double類型字段的值四舍五入保留2位小數(shù),mysql中round(col,2)可以實(shí)現(xiàn)四舍五入并且保留2位小數(shù),但是神奇的事情發(fā)生了:發(fā)現(xiàn)有的四舍五入是正確的,而有的不是我們想要的結(jié)果,如下:簡單模擬此場景:
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)
如上,有的是正確的,有的不是我們期望的值,那么問題來了,為什么呢?
通過詢問和網(wǎng)上搜索后,發(fā)現(xiàn)可能是因?yàn)?/span>double的精度問題導(dǎo)致的
查閱MySQL官當(dāng)關(guān)于double、Float、DECIMAL, NUMERIC類型的介紹,如下:
#為了說明問題,摘了官當(dāng)?shù)牟糠謨?nèi)容,關(guān)于更詳細(xì)的介紹請直接查看官當(dāng)。
12.2.3 Floating-Point Types (Approximate Value) - FLOAT, DOUBLE
#可以看到標(biāo)題已經(jīng)指出 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, seeSection B.5.5.8, “Problems with Floating-Point Values
因?yàn)?/span>Float、Double存儲的是一個近似值而不是確切的值,試圖使用它們存儲一個確切的值可以會導(dǎo)致問題。它們依賴于不同平臺和不同實(shí)現(xiàn)方式,而官當(dāng)在章節(jié)Section B.5.5.8, “Problems with Floating-Point Values中舉例說明了此問題
參考:http://dev.mysql.com/doc/refman/5.7/en/floating-point-types.html
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.
由于浮點(diǎn)數(shù)存儲的是近似值而不是確切的值,某些時候可能導(dǎo)致混亂。一個浮點(diǎn)數(shù)值在SQL語句作為內(nèi)部表示的值可能不同。試圖使用float、double來存儲確切的值可能會出現(xiàn)問題,他們也依賴不同平臺和實(shí)現(xiàn)方式。而對應(yīng)DECIMAL類型,MySQL作為65位精度進(jìn)行操作,可以解決此類精度問題。
此結(jié)果是錯誤的,盡管前5條的a和b的值看起來是不滿足a<>b條件的。
此現(xiàn)象取決于各種因素,如計(jì)算機(jī)架構(gòu)、編譯器版本或者優(yōu)化級別等。例如,不同的CPU評估的浮點(diǎn)數(shù)不同。
如果將字段d1和d2改成DECIMAL類型,將不會存在此問題。如下:
綜上,如果想精確的存儲浮點(diǎn)數(shù)值,應(yīng)該使用DECIMAL.比如金額等。
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存儲的是確切的數(shù)值,使用它們可以保證精確度,例如用于存儲金額數(shù)據(jù)。在MySQL中,NUMBERIC和DECIMAL以同樣的類型實(shí)現(xiàn)。
double類型不只是在MySQL中存在精度錯誤的問題,在oracle、Java等平臺同樣存在此問題,如下:
簡單的0.2+0.4,但是返回的結(jié)果不是0.6。
如果換成DECIMAL類型,round的結(jié)果將是正確的,如下:
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;
綜上
只為說明一個問題,如果想要確切的存儲小數(shù)(例如,金額等),建議使用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
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。