Java中浮點(diǎn)數(shù)的精度問(wèn)題
當(dāng)您在計(jì)算Money的時(shí)候,請(qǐng)看好了?。。∫粨p失了別后悔?。。?/span>
現(xiàn)象1:
public static void main(String[] args) { System.out.println(0.030*100);//輸出3.0 System.out.println(0.031*100);//輸出3.1 System.out.println(0.032*100);//輸出3.2 System.out.println(0.033*100);//輸出3.3000000000000003 System.out.println(0.034*100);//輸出3.4000000000000004 System.out.println(0.035*100);//輸出3.5000000000000004 System.out.println(0.036*100);//輸出3.5999999999999996 System.out.println(0.037*100);//輸出3.6999999999999997 System.out.println(0.038*100);//輸出3.8 System.out.println(0.039*100);//輸出3.9 } |
現(xiàn)象2:
public static void main(String[] args) { BigDecimal b1 = new BigDecimal("0.236"); BigDecimal b2 = new BigDecimal(0.236); System.out.println(b1);//輸出0.236 System.out.println(b2);//輸出0.2359999999999999875655021241982467472553253173828125 } |
描述:
當(dāng)我們使用一些“特殊的數(shù)字”進(jìn)行運(yùn)算時(shí),或者調(diào)用BigDecimal中new BigDecimal(double
val)進(jìn)行構(gòu)造的時(shí)候,將得到意想不到的結(jié)果。
原因:
Java中,浮點(diǎn)類型是依據(jù)IEEE754標(biāo)準(zhǔn)的。IEEE754定義了32位和64位雙精度兩種浮點(diǎn)二進(jìn)制小數(shù)標(biāo)準(zhǔn)。采用二進(jìn)制表示double,float等浮點(diǎn)數(shù)是不準(zhǔn)確的。
同時(shí)BigDecimal的API聲明,建議使用new BigDecimal(String val)進(jìn)行構(gòu)造,使用new BigDecimal(double val)進(jìn)行構(gòu)造的時(shí)候,將得到意想不到的結(jié)果(The results of this constructor can be
somewhat unpredictable)。
解決辦法(以0.236*100 = 23.599999999999998為例):
1、 通過(guò)String結(jié)合BigDecimal來(lái)轉(zhuǎn)換。
String val = "0.236"; //使用new BigDecimal(String val)進(jìn)行構(gòu)造 BigDecimal a = new BigDecimal(""+val); BigDecimal b = new BigDecimal(""+100); //小數(shù)的位數(shù)與構(gòu)造參數(shù)的位數(shù)一致 System.out.println(a.multiply(b));//輸出23.600 |
2、 通過(guò)移位結(jié)合BigDecimal來(lái)轉(zhuǎn)換
String val = "0.236"; //使用new BigDecimal(String val)進(jìn)行構(gòu)造 BigDecimal a = new BigDecimal(""+val); //向右移兩位 a = a.movePointRight(2); System.out.println(a);//輸出23.6 |
3、 使用保留小數(shù)位的方法來(lái)轉(zhuǎn)換
double result = 0.236*100; System.out.println(result);//輸出23.599999999999998 //計(jì)算保留result小數(shù)點(diǎn)后四位,以此類推,1后面幾個(gè)零就是保留小數(shù)點(diǎn)后幾位數(shù).如下保留兩位小數(shù) result = (double)(Math.round(result*100)/100.0)
; System.out.println(result);//輸出23.6 |
4、 使用DecimalFormat來(lái)確定小數(shù)點(diǎn)后位數(shù)
double val = 0.236*100; //保留小數(shù)點(diǎn)后兩位,若保留三位為"#.000" DecimalFormat df = new DecimalFormat("#.00"); String str = df.format(val); System.out.println(Double.valueOf(str));//輸出23.6 |
5、-----方法很多,一個(gè)即可
心得:
處理這樣的精度問(wèn)題方法很多,只要不是直接采用浮點(diǎn)數(shù)進(jìn)行計(jì)算就行。
附加:
IEEE 754用科學(xué)記數(shù)法以底數(shù)為2的小數(shù)來(lái)表示浮點(diǎn)數(shù)。32位浮點(diǎn)數(shù)用1位表示數(shù)字的符號(hào),用8位來(lái)表示指數(shù),用23位來(lái)表示尾數(shù),即小數(shù)部分。作為有符號(hào)整數(shù)的指數(shù)可以有正負(fù)之分。小數(shù)部分用二進(jìn)制(底數(shù)2)小數(shù)來(lái)表示。對(duì)于64位雙精度浮點(diǎn)數(shù),用1位表示數(shù)字的符號(hào),用11位表示指數(shù),52位表示尾數(shù)。如下兩個(gè)圖來(lái)表示:
float(32位):
1位,符號(hào)位 |
冪(8位) |
尾數(shù)(32位) |
double(64位):
1位,符號(hào)位 |
冪(11位) |
尾數(shù)(52位) |
都是分為三個(gè)部分:
(1)一個(gè)單獨(dú)的符號(hào)位s直接編碼符號(hào)s。
(2)k位的冪指數(shù)E,移碼表示。
(3)n位的小數(shù),原碼表示。
posted on 2010-10-25 21:10 kalman03 閱讀(4024) 評(píng)論(1) 編輯 收藏 所屬分類: J2EE