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

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

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

    隨筆-126  評論-247  文章-5  trackbacks-0

    來考慮這樣一種情況,先來看代碼:


    public static void main(String[] args){

            System.out.println(
    0.4 + 0.8); // = 1.2 ?
            System.out.println(2 - 1.1);      // = 0.9 ?
            System.out.println(0.2 * 3);  // = 0.6 ?
            System.out.println(1.2 / 3); // = 0.4 ?

        }
        

    也許你會天真的認為,第一行打印 1.2,第二行打印 0.9,第三行打印 0.6,第四行打印 0.4,因為依據(jù)多年的數(shù)學(xué)慣性邏輯輸出結(jié)果與預(yù)期的一致是很理所當(dāng)然的事情嘛!

    但是當(dāng)程序跑完之后,輸出的結(jié)果與預(yù)期的大有出入,來看下后臺打印的結(jié)果:


    1.2000000000000002
    0.8999999999999999
    0.6000000000000001
    0.39999999999999997
      

    結(jié)果看到這樣的結(jié)果,是不是很讓人郁悶?zāi)???dāng)然了,這些數(shù)據(jù)是我故意挑的,并不是所有涉及浮點數(shù)的運算操作都會算出這樣預(yù)期之外的結(jié)果,但是一件很明了的事情就是,

    當(dāng)操作涉及浮點數(shù)運算的時候,我們一定要謹防這樣的事情發(fā)生。

    上面代碼中,加也好,減也好,乘也好,除也好,它們都是屬于 double 級別的運算,那為什么會打印輸出這樣的結(jié)果呢?原因是,并不是所有的浮點數(shù)都能夠被精確的表示成一個

    double 類型值,有些浮點數(shù)值不能夠被精確的表示成 double 類型值,因此它會被表示成與它最接近的 double 類型的值。所以很遺憾,0.4 + 0.8 ≠ 1.2 。……

    怎么來解決這個問題呢?在 java 中提供了一個 BigDecimal 類來執(zhí)行精確小數(shù)的計算,BigDecimal 類提供了以下操作:算術(shù)、標度操作、舍入、比較、哈希算法和格式轉(zhuǎn)換。

    BigDecimal 類提供的方法:

    加法:add

    減法:subtract

    乘法:multiply

    除法:divide

     …… ……

    BigDecimal 類提供的更多的方法請自行查看 API,下面用 BigDecimal 類改寫上面的代碼實現(xiàn):


        
    public static void main(String[] args){

            System.out.println(
    new BigDecimal(0.4).add(new BigDecimal(0.8)));          // = 1.2 ?
            System.out.println(new BigDecimal(2).subtract(new BigDecimal(1.1)));    // = 0.9 ?
            System.out.println(new BigDecimal(0.2).multiply(new BigDecimal(3))); // = 0.6 ?
            System.out.println(new BigDecimal(1.2).divide(new BigDecimal(3)));     // = 0.4 ?
            
        }
        

    也許你正在查類 BigDecimal 的 API,API 上對類 BigDecimal 有一大串的文字說明,也許你還沒來得及看完,但能夠確定的是,類 BigDecimal 確實能夠準確保證精確小數(shù)的執(zhí)行,

    那我上面代碼的注釋是不是忘記去掉了啊?不是。要是真這么干,那就大禍了。先來看一下后臺的打印輸出結(jié)果:


    1.20000000000000006661338147750939242541790008544921875
    0.899999999999999911182158029987476766109466552734375
    0.600000000000000033306690738754696212708950042724609375
    Exception in thread "main" java.lang.ArithmeticException
    : Non-terminating decimal expansion; no exact representable decimal result.
        at java.math.BigDecimal.divide(BigDecimal.java:1603
    )
        at example.BigDecimalApp.main(BigDecimalApp.java:20
    )

       

    如果真這么玩了,你會看到結(jié)果更惡心了,這還不算,而且還拋了異常,這是為什么呢?別急,來看一下 API 上是怎么說的:


    public BigDecimal(double val)

        將 double 轉(zhuǎn)換為 BigDecimal,后者是 double 的二進制浮點值準確的十進制表示形式。返回的 BigDecimal 的標度是使 (10scale × val) 為整數(shù)的最小值。

    注:

    1. 此構(gòu)造方法的結(jié)果有一定的不可預(yù)知性。有人可能認為在 Java 中寫入 new BigDecimal(0.1) 所創(chuàng)建的 BigDecimal 正好等于 0.1(非標度值 1,其標度為 1),但是它實際上等于

    0.1000000000000000055511151231257827021181583404541015625。這是因為 0.1 無法準確地表示為 double (或者說對于該情況,不能表示為任何有限長度的二進制小數(shù))

    這樣,傳入 到構(gòu)造方法的值不會正好等于 0.1(雖然表面上等于該值)。

    2. 另一方面,String 構(gòu)造方法是完全可預(yù)知的:寫入 new BigDecimal("0.1") 將創(chuàng)建一個 BigDecimal,它正好 等于預(yù)期的 0.1。因此,比較而言,通常建議優(yōu)先使用 String 構(gòu)造方法

    3. 當(dāng) double 必須用作 BigDecimal 的源時,請注意,此構(gòu)造方法提供了一個準確轉(zhuǎn)換;它不提供與以下操作相同的結(jié)果:先使用 Double.toString(double) 方法,

    然后使用 BigDecimal(String) 構(gòu)造方法,將 double 轉(zhuǎn)換為 String。要獲取該結(jié)果,請使用 static valueOf(double) 方法。


    參數(shù):
        val - 要轉(zhuǎn)換為 BigDecimal 的 double 值。

    拋出: 
        NumberFormatException - 如果 val 為無窮大或 NaN。




    以上文字摘自 API,API 上解釋的很清楚了,這里就不多說了,API 建議優(yōu)先使用 String 構(gòu)造方法,那我們就來試一下唄:


        
    public static void main(String[] args){

            System.out.println(
    new BigDecimal("0.4").add(new BigDecimal("0.8")));          // = 1.2 √
            System.out.println(new BigDecimal("2").subtract(new BigDecimal("1.1")));    // = 0.9 √
            System.out.println(new BigDecimal("0.2").multiply(new BigDecimal("3"))); // = 0.6 √
            System.out.println(new BigDecimal("1.2").divide(new BigDecimal("3")));     // = 0.4 √
            
        }
        

    后臺打印輸出結(jié)果:


    1.2
    0.9
    0.6
    0.4
     

    OK,這下子終于不出簍子了,所以千萬不能隨隨便便使用 BigDecimal(double) 構(gòu)造器來創(chuàng)建 BigDecimal 對象,因為該構(gòu)造器是根據(jù)它的參數(shù)的精確值來創(chuàng)建實例對象的,

    該構(gòu)造方法的結(jié)果還是有一定的不可預(yù)知性,用 BigDecimal(String) 此構(gòu)造器來創(chuàng)建 BigDecimal 實例那就不會有問題了。

    以上提到了類 BigDecimal 中的 add 、subtract 、multiply 、divide 方法,在 API 中,你可以看到,這幾個方法都各自有自己的一個重載方法,如:

    add (BigDecimal augend, MathContext mc)  ……

    第二個參數(shù) mc 是什么意思呢?先來看一段代碼:


        
    public static void main(String[] args){

            
    //計算結(jié)果保留兩位有效數(shù)字
            System.out.println(new BigDecimal(Math.PI + "").add(new BigDecimal("0.89842"),new MathContext(2))); //輸出 4.0
            
        }
        

    第二個參數(shù) mc 是用來保留計算結(jié)果的有效位數(shù)的,其他三個方法的重載用法是一樣的,這里就不一 一列出來了。


      
    posted on 2012-08-29 11:58 fancydeepin 閱讀(9433) 評論(0)  編輯  收藏

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产午夜亚洲精品国产| 久久综合亚洲色HEZYO社区| 最近免费中文字幕大全视频| 噜噜嘿在线视频免费观看| 亚洲国产精品线观看不卡| 日韩少妇内射免费播放| 国产成人免费a在线视频app| 亚洲国产成人AV在线播放| 在线观看免费污视频| 亚洲精品无码mⅴ在线观看 | 久久亚洲色WWW成人欧美| 丁香花免费高清视频完整版| 亚洲欧洲日产国码无码网站| 亚洲欧美熟妇综合久久久久| 午夜老司机免费视频| 久久精品亚洲日本波多野结衣 | 亚洲αv在线精品糸列| 国产免费爽爽视频在线观看| 亚洲久本草在线中文字幕| 特级毛片全部免费播放a一级| 亚洲毛片免费视频| 亚洲国产午夜精品理论片| 成年人免费观看视频网站| 怡红院亚洲红怡院在线观看| 亚洲色偷拍区另类无码专区| 免费看无码特级毛片| 亚洲欧洲精品成人久久奇米网| 99久久婷婷国产综合亚洲| 午夜成人免费视频| 亚洲熟妇无码八V在线播放| 免费国产成人高清在线观看麻豆| av片在线观看永久免费| 亚洲首页在线观看| 国产一区二区三区在线观看免费| 国产久爱免费精品视频| 亚洲网站视频在线观看| 国产大片51精品免费观看| 成全在线观看免费观看大全| 国产精品高清视亚洲精品| 四虎永久成人免费| 97免费人妻在线视频|