- Java開(kāi)發(fā)之道
- 張振坤 李鐘尉 陳丹丹等編著
- 1268字
- 2018-12-27 19:53:53
陷阱2 差值損失——浮點(diǎn)數(shù)相減造成的損失
對(duì)于浮點(diǎn)數(shù)相減,有時(shí)結(jié)果是正確的,有時(shí)結(jié)果是不正確的,所以在使用浮點(diǎn)數(shù)進(jìn)行相減運(yùn)算時(shí),一定要注意應(yīng)用的領(lǐng)域,特別是對(duì)于一些精密儀器的計(jì)算、導(dǎo)彈運(yùn)行軌跡的運(yùn)算以及航空母艦的運(yùn)行軌跡,等等,一定要保證結(jié)果的正確性,稍有差異可能就會(huì)造成很大偏差或脫離軌道,由此造成的損失將是巨大的。
接下來(lái)通過(guò)兩個(gè)示例來(lái)說(shuō)明浮點(diǎn)數(shù)相減的結(jié)果有時(shí)是正確的,而有時(shí)是不正確的。
(1)計(jì)算結(jié)果正確的示例
示例:
double result = 1.00 - 0.10 ; // 將兩個(gè)浮點(diǎn)數(shù)的差賦值給變量result System. out. println (result) ; // 輸出差值,也就是變量result的值
說(shuō)明
上面示例輸出result的值是0.9,這種情況屬于正常的結(jié)果,因?yàn)榇_實(shí)1.00減去0.10的差應(yīng)該是0.9。
(2)計(jì)算結(jié)果不正確的示例
示例:
double result = 3.00 - 2.60 ; // 將兩個(gè)浮點(diǎn)數(shù)的差賦值給變量result System. out. println (result) ; // 輸出差值,也就是變量result的值
說(shuō)明
上面示例輸出result 的值是0.3999999999999999,這種情況屬于不正確的結(jié)果,因?yàn)?.00減去2.60的正確差值應(yīng)該是0.4。
由于浮點(diǎn)數(shù)相減結(jié)果錯(cuò)誤,很有可能會(huì)造成不可估量的損失,尤其是對(duì)于一些精密的計(jì)算,因此必須要對(duì)浮點(diǎn)數(shù)相減運(yùn)算進(jìn)行處理,使其能計(jì)算出正確的結(jié)果。
下面是能夠保證浮點(diǎn)數(shù)相減計(jì)算結(jié)果正確的兩種方法。
(1)使用BigDecimal類
使用BigDecimal類對(duì)浮點(diǎn)數(shù)進(jìn)行封裝,然后通過(guò)該類的subtract ()方法計(jì)算兩個(gè)數(shù)的差,這樣就可以保證計(jì)算結(jié)果的正確性,但是前提是一定要用String 類型形參的構(gòu)造方法,而不要用其他類型形參的構(gòu)造方法創(chuàng)建BigDecimal對(duì)象,否則也會(huì)出現(xiàn)結(jié)果不正確的現(xiàn)象。
示例:
BigDecimal num1 = new BigDecimal ("3.00") ; // 使用字符串創(chuàng)建BigDecimal對(duì)象num1 BigDecimal num2 = new BigDecimal ("2.60") ; // 使用字符串創(chuàng)建BigDecimal對(duì)象num2 BigDecimal num3 = num1. subtract (num2) ; // 計(jì)算BigDecimal對(duì)象num1與num2的差 double value = num3. doubleValue () ; // 將差值num3轉(zhuǎn)換為double型賦值給變量value System. out. println (value) ; // 輸出差值,即輸出value的值
說(shuō)明
上面示例輸出value的值是0.4,這是正確的結(jié)果,從而解決了浮點(diǎn)數(shù)相減錯(cuò)誤的問(wèn)題,但是這種做法可能會(huì)造成程序運(yùn)行速度的下降,因?yàn)樵擃惒](méi)有很好地得到Java語(yǔ)言的支持。
(2)轉(zhuǎn)換為整數(shù)
由于BigDecimal類沒(méi)有很好地得到Java語(yǔ)言的支持,因此可以使用另一種方法來(lái)解決浮點(diǎn)數(shù)相減的問(wèn)題,那就是將原來(lái)的數(shù)轉(zhuǎn)換為整數(shù),例如,將3.00和2.60各乘以100,并將結(jié)果強(qiáng)制轉(zhuǎn)換為int型或long型,然后對(duì)整數(shù)做減法運(yùn)算,并將運(yùn)算結(jié)果轉(zhuǎn)換為浮點(diǎn)數(shù),方法是用差值除以100.0,從而得到最終的結(jié)果,這種做法程序的運(yùn)行速度較快。
示例:
double dbNum1 = 3.00 ; // 定義double型變量dbNum1,其值是3.00 double dbNum2 = 2.60 ; // 定義double型變量dbNum2,其值是2.60 long lngNum1 = (long) (dbNum1 * 100) ; // 將dbNum1的值乘以100后,轉(zhuǎn)換為long型 long lngNum2 = (long) (dbNum2 * 100) ; // 將dbNum2的值乘以100后,轉(zhuǎn)換為long型 long lngResult = lngNum1 - lngNum2 ; // 計(jì)算兩個(gè)long型值的差并賦值給變量lngResult double dbResult = lngResult / 100.0 ; // 用long型差值除以100.0,即轉(zhuǎn)換為double型 System. out. println (dbResult) ; // 輸出最終結(jié)果
說(shuō)明
上面示例輸出dbResult的值是0.4,這是正確的結(jié)果,從而解決了浮點(diǎn)數(shù)相減錯(cuò)誤的問(wèn)題,并且這種做法速度更快,因此,對(duì)于頻繁的浮點(diǎn)數(shù)相減運(yùn)算就應(yīng)盡量采用這種方法來(lái)實(shí)現(xiàn),當(dāng)然計(jì)算頻率較少時(shí),可以使用BigDecimal類來(lái)實(shí)現(xiàn)。
編程準(zhǔn)則:盡量將浮點(diǎn)數(shù)相減轉(zhuǎn)換為整數(shù)相減
在進(jìn)行浮點(diǎn)數(shù)相減運(yùn)算時(shí),除非對(duì)精度要求不高,否則應(yīng)該將浮點(diǎn)數(shù)轉(zhuǎn)換為整數(shù),然后再對(duì)轉(zhuǎn)換后的整數(shù)進(jìn)行相減運(yùn)算,最后再對(duì)計(jì)算結(jié)果進(jìn)行處理,將其轉(zhuǎn)換為浮點(diǎn)數(shù),這樣就可以得到精確的結(jié)果。
- 機(jī)器學(xué)習(xí)系統(tǒng):設(shè)計(jì)和實(shí)現(xiàn)
- Internet of Things with the Arduino Yún
- 深入淺出RxJS
- Python Data Structures and Algorithms
- Visual Basic程序設(shè)計(jì)教程
- C++寶典
- “笨辦法”學(xué)C語(yǔ)言
- JBoss:Developer's Guide
- Visual Studio Code 權(quán)威指南
- Modernizing Legacy Applications in PHP
- Access數(shù)據(jù)庫(kù)應(yīng)用教程(2010版)
- WCF技術(shù)剖析(卷1)
- Java EE項(xiàng)目應(yīng)用開(kāi)發(fā)
- 少兒編程輕松學(xué)(全2冊(cè))
- Java Web動(dòng)態(tài)網(wǎng)站開(kāi)發(fā)(第2版·微課版)