<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    磨刀不誤砍柴工

    合抱之木,生于毫末;九層之臺,起于累土;千里之行,始于足下。

       ::  ::  ::  :: 管理

    Java 浮點(diǎn)數(shù)精確計(jì)算 BigDecimal的用法

    java.math.BigDecimal的用法?

    Java 浮點(diǎn)數(shù) 精確計(jì)算  

    如果我們編譯運(yùn)行下面這個(gè)程序會看到什么?

    public class Test{

        public static void main(String args[]){

            System.out.println(0.05+0.01);

            System.out.println(1.0-0.42);

            System.out.println(4.015*100);

            System.out.println(123.3/100);

        }

    };

    你沒有看錯(cuò)!結(jié)果確實(shí)是

    0.060000000000000005

    0.5800000000000001

    401.49999999999994

    1.2329999999999999

    Java中的簡單浮點(diǎn)數(shù)類型float和double不能夠進(jìn)行運(yùn)算。不光是Java,在其它很多編程語言中也有這樣的問題。在大多數(shù)情況下,計(jì)算的結(jié)果是準(zhǔn)確的,但是多試幾次(可以做一個(gè)循環(huán))就可以試出類似上面的錯(cuò)誤。現(xiàn)在終于理解為什么要有BCD碼了。

    這個(gè)問題相當(dāng)嚴(yán)重,如果你有9.999999999999元,你的計(jì)算機(jī)是不會認(rèn)為你可以購買10元的商品的。

    在有的編程語言中提供了專門的貨幣類型來處理這種情況,但是Java沒有。現(xiàn)在讓我們看看如何解決這個(gè)問題。

    四舍五入

    我們的第一個(gè)反應(yīng)是做四舍五入。Math類中的round方法不能設(shè)置保留幾位小數(shù),我們只能象這樣(保留兩位):

    public double round(double value){

        return Math.round(value*100)/100.0;

    }

    非常不幸,上面的代碼并不能正常工作,給這個(gè)方法傳入4.015它將返回4.01而不是4.02,如我們在上面看到的

    4.015*100=401.49999999999994

    因此如果我們要做到精確的四舍五入,不能利用簡單類型做任何運(yùn)算

    java.text.DecimalFormat也不能解決這個(gè)問題:

    System.out.println(new java.text.DecimalFormat("0.00").format(4.025));

    輸出是4.02

    BigDecimal

    在《Effective Java》這本書中也提到這個(gè)原則,float和double只能用來做科學(xué)計(jì)算或者是工程計(jì)算,在商業(yè)計(jì)算中我們要用 java.math.BigDecimal。BigDecimal一共有4個(gè)夠造方法,我們不關(guān)心用BigInteger來夠造的那兩個(gè),那么還有兩個(gè),它們是:

    BigDecimal(double val)

              Translates a double into a BigDecimal.

    BigDecimal(String val)

              Translates the String repre sentation of a BigDecimal into a BigDecimal.

    上面的API簡要描述相當(dāng)?shù)拿鞔_,而且通常情況下,上面的那一個(gè)使用起來要方便一些。我們可能想都不想就用上了,會有什么問題呢?等到出了問題的時(shí)候,才發(fā)現(xiàn)上面哪個(gè)夠造方法的詳細(xì)說明中有這么一段:

    Note: the results of this constructor can be somewhat unpredictable. One might assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal to .1000000000000000055511151231257827021181583404541015625. This is so because .1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the long value that is being passed in to the constructor is not exactly equal to .1, appearances nonwithstanding.

    The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one.

    原來我們?nèi)绻枰_計(jì)算,非要用String來夠造BigDecimal不可!在《Effective Java》一書中的例子是用String來夠造BigDecimal的,但是書上卻沒有強(qiáng)調(diào)這一點(diǎn),這也許是一個(gè)小小的失誤吧。

    解決方案

    現(xiàn)在我們已經(jīng)可以解決這個(gè)問題了,原則是使用BigDecimal并且一定要用String來夠造。

    但是想像一下吧,如果我們要做一個(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ù)。你能夠忍受這么煩瑣的過程嗎?下面我們提供一個(gè)工具類Arith來簡化操作。它提供以下靜態(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)

    附錄

     


     

    BigDecimal舍入模式(Rounding mode)
    關(guān)鍵字: bigdecimal

    ROUND_CEILING
    Rounding mode to round towards positive infinity.
    向正無窮方向舍入
    ROUND_DOWN
    Rounding mode to round towards zero.
    向零方向舍入
    ROUND_FLOOR
    Rounding mode to round towards negative infinity.
    向負(fù)無窮方向舍入
    ROUND_HALF_DOWN
    Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
    向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向下舍入, 例如1.55 保留一位小數(shù)結(jié)果為1.5
    ROUND_HALF_EVEN
    Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
    向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,如果保留位數(shù)是奇數(shù),使用ROUND_HALF_UP ,如果是偶數(shù),使用ROUND_HALF_DOWN
    ROUND_HALF_UP
    Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
    向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向上舍入, 1.55保留一位小數(shù)結(jié)果為1.6
    ROUND_UNNECESSARY
    Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
    計(jì)算結(jié)果是精確的,不需要舍入模式
    ROUND_UP
    Rounding mode to round away from zero.
    向遠(yuǎn)離0的方向舍入
    例子

    Java代碼

    1. BigDecimal n3  = new BigDecimal(1.2345678901234567890E+9);  
    2. System.out.println(n3) 
    BigDecimal n3  = new BigDecimal(1.2345678901234567890E+9);
    System.out.println(n3)

    這樣輸出的結(jié)果是:1234567890.1234567165374755859375
    當(dāng)?shù)搅撕竺?7位之后就開始不準(zhǔn)確了
    因Double類型本身只能精確到17位
    但是如果這樣

    Java代碼

    1. BigDecimal n4  = new BigDecimal("1.23456789012345678901234567890E+9"); 
    BigDecimal n4  = new BigDecimal("1.23456789012345678901234567890E+9");
    

    結(jié)果是1234567891.12345678901234567890
    這樣就能絕對精確
    posted on 2010-01-27 12:06 liwei5891 閱讀(520) 評論(0)  編輯  收藏 所屬分類: Java

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 91丁香亚洲综合社区| 日韩av无码久久精品免费| 免费观看黄网站在线播放| 久久久久久亚洲精品成人| 插鸡网站在线播放免费观看| 国产在线98福利播放视频免费| 亚洲人成图片网站| 成人毛片免费观看视频大全| 国产亚洲精品影视在线| 免费人成视频在线| 国产精品亚洲专区无码WEB| 日本不卡视频免费| 色婷婷综合缴情综免费观看| 亚洲精品无码你懂的网站| 一级特黄a大片免费| 亚洲欧洲无码AV电影在线观看| 99在线热播精品免费99热| 亚洲av伊人久久综合密臀性色 | 久久国产色AV免费看| 精品亚洲aⅴ在线观看| 免费看美女裸露无档网站| 亚洲欧美日韩综合久久久 | 国产福利免费观看| 深夜福利在线视频免费| 亚洲色欲久久久综合网| 88av免费观看| 亚洲深深色噜噜狠狠网站| 国产精品久久香蕉免费播放| XXX2高清在线观看免费视频| 久久久久亚洲av无码专区喷水| 日本妇人成熟免费中文字幕| 春暖花开亚洲性无区一区二区| 最新亚洲成av人免费看| 99在线热视频只有精品免费| 亚洲日本中文字幕天天更新| 亚洲精品无码专区2| 99久久国产免费中文无字幕| 亚洲砖码砖专无区2023| 国产亚洲情侣一区二区无| h视频在线免费看| 二级毛片免费观看全程|