你知道MySQL中Decimal類型和Float Double的區(qū)別嗎?

出處:cnblogs.com/panchanggui/p/10766607.html
MySQL中存在float,double等非標(biāo)準(zhǔn)數(shù)據(jù)類型,也有decimal這種標(biāo)準(zhǔn)數(shù)據(jù)類型。
其區(qū)別在于,float,double等非標(biāo)準(zhǔn)類型,在DB中保存的是近似值,而Decimal則以字符串的形式保存數(shù)值。
float,double類型是可以存浮點(diǎn)數(shù)(即小數(shù)類型),但是float有個(gè)壞處,當(dāng)你給定的數(shù)據(jù)是整數(shù)的時(shí)候,那么它就以整數(shù)給你處理。這樣我們?cè)诖嫒∝泿胖档臅r(shí)候自然遇到問(wèn)題,我的default值為:0.00而實(shí)際存儲(chǔ)是0,同樣我存取貨幣為12.00,實(shí)際存儲(chǔ)是12。
幸好mysql提供了兩個(gè)數(shù)據(jù)類型:decimal,這種數(shù)據(jù)類型可以輕松解決上面的問(wèn)題:decimal類型被 MySQL 以同樣的類型實(shí)現(xiàn),這在 SQL92 標(biāo)準(zhǔn)中是允許的。他們用于保存對(duì)準(zhǔn)確精度有重要要求的值,例如與金錢有關(guān)的數(shù)據(jù)。
數(shù)據(jù)定義
float(M,S) M為全長(zhǎng),S為小數(shù)點(diǎn)后長(zhǎng)度。
數(shù)據(jù)庫(kù)類型和Java類型之間的關(guān)系:???????
? ? ? ?
? ? ?DBC?Type????????????Java?Type?
????CHAR? ? ? ? ? ? ? ? ? ?String?
????VARCHAR?????????????String?
????LONGVARCHAR???????????String?
????NUMERIC?????????????java.math.BigDecimal?
????DECIMAL?????????????java.math.BigDecimal?
????BIT???????????????boolean
????BOOLEAN?????????????boolean?
????TINYINT?????????????byte?
????SMALLINT? ? ? ? ? ? ? ??short?
????INTEGER?????????????int?
????BIGINT????????????? long?
????REAL? ? ? ? ? ? ? ? ? ?float?
????FLOAT??????????????double?
????DOUBLE? ? ? ? ? ? ? ? ??double?
????BINARY? ? ? ? ? ? ? ? ??byte[]?
????VARBINARY????????????byte[]?
????LONGVARBINARY??????????byte[]?
????DATE? ? ? ? ? ? ? ? ? ?java.sql.Date?
????TIME? ? ? ? ? ? ? ? ? ?java.sql.Time?
????TIMESTAMP????????????java.sql.Timestamp?
????CLOB? ? ? ? ? ? ? ? ? ?Clob?
????BLOB? ? ? ? ? ? ? ? ? ?Blob?
????ARRAY??????????????Array?
????DISTINCT? ? ? ? ? ? ? ??mapping?of?underlying?type?
????STRUCT? ? ? ? ? ? ? ? ?Struct?
????REF???????????????Ref項(xiàng)目中BigDecimal與Double使用場(chǎng)景
金額要用BigDecimal,金額計(jì)算不能用doube!!!!
金額計(jì)算必須用BigDecimal,下面對(duì)比一下用double 跟BigDecimal的區(qū)別。先看一個(gè)小例子:
請(qǐng)看題:

示例1
問(wèn), 結(jié)果是多少? 0.01?
No! 結(jié)果是0.009999999999999998!
為什么會(huì)這樣呢? 因?yàn)閒loat和double都是浮點(diǎn)數(shù), 都有取值范圍, 都有精度范圍. 浮點(diǎn)數(shù)與通常使用的小數(shù)不同, 使用中, 往往難以確定.
常見(jiàn)的問(wèn)題是定義了一個(gè)浮點(diǎn)數(shù), 經(jīng)過(guò)一系列的計(jì)算, 它本來(lái)應(yīng)該等于某個(gè)確定值, 但實(shí)際上并不是!
double相減會(huì)轉(zhuǎn)換成二進(jìn)制,因double有效位數(shù)為 16位這就會(huì)出現(xiàn)存儲(chǔ)小數(shù)位數(shù)不夠的情況,這種情況下就會(huì)出現(xiàn)誤差,解決方法就是使用BigDecimal,它的有效長(zhǎng)度足夠長(zhǎng)可存儲(chǔ)小數(shù)位數(shù)。
因此可代替double來(lái)進(jìn)行加減乘除,?金額必須是完全精確的計(jì)算, 故不能使用double或者float, 而應(yīng)該采用java.math.BigDecimal.
加減乘除
兩個(gè)BigDecimal值應(yīng)該怎樣進(jìn)行加減乘除呢? +, -, *, / 這樣寫嗎? 不!
請(qǐng)看示例:

加減乘除使用了英文的加減乘除, 即add, substract, multiply和divide
大小比較
兩個(gè)BigDecimal值怎么比較大小呢? 能用>或者<嗎? 也不可以!

兩個(gè)BigDecimal值比較使用compareTo方法, 比較結(jié)果有-1, 0, 1, 分別表示小于, 等于, 大于; 對(duì)于0, 可以使用BigDecimal.ZERO表示!
四舍五入

簡(jiǎn)化BigDecimal計(jì)算的小工具類
如果我們要做一個(gè)加法運(yùn)算,需要先將兩個(gè)浮點(diǎn)數(shù)轉(zhuǎn)為String,然后夠造成BigDecimal,在其中一個(gè)上調(diào)用add方法,傳入另一個(gè)作為參數(shù),然后把運(yùn)算的結(jié)果(BigDecimal)再轉(zhuǎn)換為浮點(diǎn)數(shù)。
你能夠忍受這么煩瑣的過(guò)程嗎?
網(wǎng)上提供的工具類Arith來(lái)簡(jiǎn)化操作。它提供以下靜態(tài)方法,包括加減乘除和四舍五入:??
public???static???double???add(double???v1,double???v2)???
public???static???double???sub(double???v1,double???v2)???
public???static???double???mul(double???v1,double???v2)???
public???static???double???div(double???v1,double???v2)???
public???static???double???div(double???v1,double???v2,int???scale)???
public???static???double???round(double???v,int???scale)定點(diǎn)數(shù)和浮點(diǎn)數(shù)的區(qū)別
在計(jì)算機(jī)系統(tǒng)的發(fā)展過(guò)程中,曾經(jīng)提出過(guò)多種方法表達(dá)實(shí)數(shù)。典型的比如相對(duì)于浮點(diǎn)數(shù)的定點(diǎn)數(shù)(Fixed Point Number)。在這種表達(dá)方式中,小數(shù)點(diǎn)固定的位于實(shí)數(shù)所有數(shù)字中間的某個(gè)位置。
貨幣的表達(dá)就可以使用這種方式,比如 99.00 或者 00.99 可以用于表達(dá)具有四位精度(Precision),小數(shù)點(diǎn)后有兩位的貨幣值。由于小數(shù)點(diǎn)位置固定,所以可以直接用四位數(shù)值來(lái)表達(dá)相應(yīng)的數(shù)值。
SQL 中的 NUMBER 數(shù)據(jù)類型就是利用定點(diǎn)數(shù)來(lái)定義的。還有一種提議的表達(dá)方式為有理數(shù)表達(dá)方式,即用兩個(gè)整數(shù)的比值來(lái)表達(dá)實(shí)數(shù)。
定點(diǎn)數(shù)表達(dá)法的缺點(diǎn)在于其形式過(guò)于僵硬,固定的小數(shù)點(diǎn)位置決定了固定位數(shù)的整數(shù)部分和小數(shù)部分,不利于同時(shí)表達(dá)特別大的數(shù)或者特別小的數(shù)。
最終,絕大多數(shù)現(xiàn)代的計(jì)算機(jī)系統(tǒng)采納了所謂的浮點(diǎn)數(shù)表達(dá)方式。這種表達(dá)方式利用科學(xué)計(jì)數(shù)法來(lái)表達(dá)實(shí)數(shù),即用一個(gè)尾數(shù)(Mantissa ),一個(gè)基數(shù)(Base),一個(gè)指數(shù)(Exponent)以及一個(gè)表示正負(fù)的符號(hào)來(lái)表達(dá)實(shí)數(shù)。
比如 123.45 用十進(jìn)制科學(xué)計(jì)數(shù)法可以表達(dá)為 1.2345 × 102 ,其中 1.2345 為尾數(shù),10 為基數(shù),2 為指數(shù)。浮點(diǎn)數(shù)利用指數(shù)達(dá)到了浮動(dòng)小數(shù)點(diǎn)的效果,從而可以靈活地表達(dá)更大范圍的實(shí)數(shù)。
在MySQL中使用浮點(diǎn)數(shù)類型和定點(diǎn)數(shù)類型來(lái)表示小數(shù)。浮點(diǎn)數(shù)類型包括單精度浮點(diǎn)數(shù)(FLOAT型)和雙精度浮點(diǎn)數(shù)(DOUBLE型)。定點(diǎn)數(shù)類型就是DECIMAL型。MySQL的浮點(diǎn)數(shù)類型和定點(diǎn)數(shù)類型如下表所示:
| 類型名稱 | 字節(jié)數(shù) | 負(fù)數(shù)的取值范圍 | 非負(fù)數(shù)的取值范圍 |
|---|---|---|---|
| FLOAT | 4 | -3.402823466E+38~ -1.175494351E-38 | 0和1.175494351E-38~ 3.402823466E+38 |
| DOUBLE | 8 | -1.7976931348623157E+308~ -2.2250738585072014E-308 | 0和2.2250738585072014E-308~ 1.7976931348623157E+308 |
| DECIMAL(M,D)或DEC(M,D) | M+2 | 同DOUBLE型 | 同DOUBLE型 |
從上表中可以看出,DECIMAL型的取值范圍與DOUBLE相同。但是,DECIMAL的有效取值范圍由M和D決定,而且DECIMAL型的字節(jié)數(shù)是M+2,也就是說(shuō),定點(diǎn)數(shù)的存儲(chǔ)空間是根據(jù)其精度決定的。
?MySQL
?BigDecimal在進(jìn)行入庫(kù)時(shí), 數(shù)據(jù)庫(kù)選擇decimal類型, 長(zhǎng)度可以自定義, 如18; 小數(shù)點(diǎn)我們項(xiàng)目中用的是2, 保留2位小數(shù). 此外還要注意的就是默認(rèn)值, 一定寫成0.00, 不要用默認(rèn)的NULL, 否則在進(jìn)行加減排序等操作時(shí), 會(huì)帶來(lái)轉(zhuǎn)換的麻煩!
`balance`?decimal(18,2) DEFAULT '0.00'?COMMENT '賬戶余額',MySQL DECIMAL數(shù)據(jù)類型用于在數(shù)據(jù)庫(kù)中存儲(chǔ)精確的數(shù)值。我們經(jīng)常將DECIMAL數(shù)據(jù)類型用于保留準(zhǔn)確精確度的列,例如會(huì)計(jì)系統(tǒng)中的貨幣數(shù)據(jù)。
要定義數(shù)據(jù)類型為DECIMAL的列,請(qǐng)使用以下語(yǔ)法:
column_name DECIMAL(P,D);在上面的語(yǔ)法中:
P是表示有效數(shù)字?jǐn)?shù)的精度。
P范圍為1?65。
D是表示小數(shù)點(diǎn)后的位數(shù)。
D的范圍是0~30。
MySQL要求D小于或等于(<=)P。
DECIMAL(P,D)表示列可以存儲(chǔ)D位小數(shù)的P位數(shù)。十進(jìn)制列的實(shí)際范圍取決于精度和刻度。
與INT數(shù)據(jù)類型一樣,DECIMAL類型也具有UNSIGNED和ZEROFILL屬性。如果使用UNSIGNED屬性,則DECIMAL UNSIGNED的列將不接受負(fù)值。
如果使用ZEROFILL,MySQL將把顯示值填充到0以顯示由列定義指定的寬度。另外,如果我們對(duì)DECIMAL列使用ZERO FILL,MySQL將自動(dòng)將UNSIGNED屬性添加到列。
以下示例使用DECIMAL數(shù)據(jù)類型定義的一個(gè)叫作amount的列。
amount DECIMAL(6,2);在此示例中,amount列最多可以存儲(chǔ)6位數(shù)字,小數(shù)位數(shù)為2位; 因此,amount列的范圍是從-9999.99到9999.99。
