<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,因為依據多年的數學慣性邏輯輸出結果與預期的一致是很理所當然的事情嘛!

    但是當程序跑完之后,輸出的結果與預期的大有出入,來看下后臺打印的結果:


    1.2000000000000002
    0.8999999999999999
    0.6000000000000001
    0.39999999999999997
      

    結果看到這樣的結果,是不是很讓人郁悶呢?當然了,這些數據是我故意挑的,并不是所有涉及浮點數的運算操作都會算出這樣預期之外的結果,但是一件很明了的事情就是,

    當操作涉及浮點數運算的時候,我們一定要謹防這樣的事情發生。

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

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

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

    BigDecimal 類提供的方法:

    加法:add

    減法:subtract

    乘法:multiply

    除法:divide

     …… ……

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


        
    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 確實能夠準確保證精確小數的執行,

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


    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
    )

       

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


    public BigDecimal(double val)

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

    注:

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

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

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

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

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

    然后使用 BigDecimal(String) 構造方法,將 double 轉換為 String。要獲取該結果,請使用 static valueOf(double) 方法。


    參數:
        val - 要轉換為 BigDecimal 的 double 值。

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




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


        
    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 √
            
        }
        

    后臺打印輸出結果:


    1.2
    0.9
    0.6
    0.4
     

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

    該構造方法的結果還是有一定的不可預知性,用 BigDecimal(String) 此構造器來創建 BigDecimal 實例那就不會有問題了。

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

    add (BigDecimal augend, MathContext mc)  ……

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


        
    public static void main(String[] args){

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

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


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

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


    網站導航:
     
    主站蜘蛛池模板: 风间由美在线亚洲一区| 国产AV无码专区亚洲AWWW| 91麻豆国产自产在线观看亚洲| 亚洲av专区无码观看精品天堂 | 亚洲精品美女网站| 久久精品中文字幕免费| 永久亚洲成a人片777777| 免费精品久久久久久中文字幕| 天天看免费高清影视| 亚洲激情视频网站| 99在线在线视频免费视频观看| 国产aⅴ无码专区亚洲av麻豆| 免费在线观看自拍性爱视频| 大学生高清一级毛片免费| 456亚洲人成影院在线观| 亚洲性线免费观看视频成熟 | 无码精品一区二区三区免费视频 | 国产成人综合亚洲亚洲国产第一页 | 久久精品免费视频观看| 亚洲av无码国产精品色午夜字幕 | 亚洲AV无码久久精品色欲| 国产精品偷伦视频免费观看了| 亚洲国产成人精品无码久久久久久综合 | 亚洲精品国产手机| 亚洲美女视频免费| 亚洲av无码一区二区三区天堂古代| 99爱在线精品免费观看| 亚洲国产视频一区| 免费精品人在线二线三线区别| 国产成人精品日本亚洲18图| 成人性生交视频免费观看| 亚洲AV无码一区二区三区久久精品| 日本黄色免费观看| 全部在线播放免费毛片| 亚洲人成人无码网www电影首页| 最新国产乱人伦偷精品免费网站| 亚洲av无码不卡一区二区三区| 91精品免费久久久久久久久| 亚洲免费网站在线观看| 狼友av永久网站免费观看| 黄色免费在线观看网址|