官术网_书友最值得收藏!

陷阱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é)果。

主站蜘蛛池模板: 新竹市| 宁都县| 柏乡县| 黄山市| 喀喇沁旗| 漳平市| 贡山| 武宁县| 张北县| 罗山县| 渭南市| 启东市| 龙海市| 达州市| 永登县| 阿拉尔市| 木兰县| 肇东市| 衡东县| 大竹县| 白山市| 彩票| 屏边| 互助| 郁南县| 长寿区| 江西省| 长治县| 泽库县| 岱山县| 郸城县| 宜君县| 德格县| 博罗县| 台北市| 胶南市| 通山县| 康保县| 萨迦县| 耒阳市| 金门县|