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

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

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

    posts - 40,  comments - 187,  trackbacks - 0

    說在前面的話

            先祝各位看官在虎年里虎虎生威,財源廣進,萬事如意!


            Java 語言支持兩種基本的浮點類型: floatdouble ,以及與它們對應的包裝類 FloatDouble 。它們都依據 IEEE 754 標準,該標準為 32 位浮點和 64 位雙精度浮點二進制小數定義了二進制標準。
            但是在一些項目中,一些非整數值(如幾元和幾分這樣的小數)需要很精確。所以,不要用浮點數表示精確值。浮點數不是精確值,所以使用它們會導致舍入誤差。因此,使用浮點數來試圖表示象貨幣量這樣的精確數量不是一個好的想法。使用浮點數來進行元和分計算會得到災難性的后果。浮點數最好用來表示象測量值這類數值,這類值從一開始就不怎么精確。
            所以一般對double類型進行運算時,做好對結果進行處理,然后拿這個值去做其他事情。 下面我們就用代碼來說明一下如何對浮點數進行精度計算,以double為例。


    詳細代碼(注釋很詳細 不做解釋了)  可點擊這里下載代碼

    /*
     * Copyright reserved 2010 by AllensLab
     * @project AllensLab
     * @date Feb 22, 2010
     
    */

    package cn.allen.tools;

    import
     java.math.BigDecimal;

    /**
     * RoundTool
     * 
    @author allen
     * @time 10:05:40 AM Feb 22, 2010
     
    */

    public class RoundTools {
        
    /**  
         * 對double數據進行取精度.  
         * <p>  
         * For example: <br>  
         * double value = 100.345678; <br>  
         * double ret = round(value,4,BigDecimal.ROUND_HALF_UP); <br>  
         * ret為100.3457 <br>  
         *   
         * 
    @param
     value  
         *            double數據.  
         * 
    @param
     scale  
         *            精度位數(保留的小數位數).  
         * 
    @param
     roundingMode  
         *            精度取值方式.  
         * 
    @return
     精度計算后的數據.  
         
    */

        
    public static double round(double value, int scale, int roundingMode) {
            BigDecimal bd 
    = new
     BigDecimal(value);
            bd 
    =
     bd.setScale(scale, roundingMode);
            
    double d =
     bd.doubleValue();
            bd 
    = null
    ;
            
    return
     d;
        }

        
        
    public static BigDecimal roundAgain(double value, int scale, int roundingMode) {
            BigDecimal bd 
    = new
     BigDecimal(value);
            bd 
    =
     bd.setScale(scale, roundingMode);
            
    return
     bd;
        }

        
        
    /* 用于加、減、乘和除的方法給 BigDecimal 值提供了算術運算。由于 BigDecimal 對象是不可變的,這些方法中的每一個都會產生新的 BigDecimal 對象。
         * 因為創建對象的開銷, BigDecimal 不適合于大量的數學計算,但設計它的目的是用來精確地表示小數。 
    */

        
        
    /**
         * Addition
         * 
    @param number1
         * 
    @param
     number2
         * 
    @return

         * 
    @author allen
         * @date 10:42:47 AM Feb 22, 2010
         
    */

        
    public static double add(double number1, double number2, int newScale, int roundingMode) {
            
    return
     BigDecimal.valueOf(number1).add(BigDecimal.valueOf(number2)).setScale(newScale, roundingMode).doubleValue();
        }

        
        
    public static double add(int newScale, int roundingMode, double number1, double numbers) {
            BigDecimal bd 
    = new
     BigDecimal(number1);
            
    for (double number : numbers) 
    {
                bd 
    =
     bd.add(BigDecimal.valueOf(number).setScale(newScale, roundingMode));
            }

            
    return bd.doubleValue();
        }

        
        
    /**
         * Subtraction
         * 
    @param number1
         * 
    @param
     number2
         * 
    @return

         * 
    @author allen
         * @date 10:45:36 AM Feb 22, 2010
         
    */

        
    public static double subtract(double number1, double number2, int newScale, int roundingMode) {
            
    return
     BigDecimal.valueOf(number1).subtract(BigDecimal.valueOf(number2)).setScale(newScale, roundingMode).doubleValue();
        }

        
        
    /**
         * Multiplication 
         * 
    @param number1
         * 
    @param
     number2
         * 
    @return

         * 
    @author allen
         * @date 10:46:23 AM Feb 22, 2010
         
    */

        
    public static double multiply(double number1, double number2, int newScale, int roundingMode) {
            
    return
     BigDecimal.valueOf(number1).multiply(BigDecimal.valueOf(number2)).setScale(newScale, roundingMode).doubleValue();
            
        }

        
        
    /**
         * Division
         * 盡量采用財務常用的四舍六入五取偶 即ROUND_HALF_EVEN
         * 
    @param number1
         * 
    @param
     number2
         * 
    @return

         * 
    @author allen
         * @date 10:47:12 AM Feb 22, 2010
         
    */

        
    public static double divide(double number1, double number2, int scale, int roundingMode) {
            
    return
     BigDecimal.valueOf(number1).divide(BigDecimal.valueOf(number2), scale, roundingMode).doubleValue();
        }

        
        
    /**  
         * 測試用的main方法.  
         *   
         * 
    @param
     args  
         *            運行參數.  
         
    */

        
    public static void main(String[] args) {
            
    //下面都以保留2位小數為例   

            System.out.println(add(12.34112.34492, BigDecimal.ROUND_HALF_EVEN));
            System.out.println(add(
    2, BigDecimal.ROUND_HALF_UP, 12.34612.344912.340112.345
    ));
            System.out.println(subtract(
    12.344912.3412
    , BigDecimal.ROUND_HALF_EVEN));
            System.out.println(multiply(
    12.34490.012
    , BigDecimal.ROUND_HALF_UP));
            System.out.println(divide(
    11.34112.3462
    , BigDecimal.ROUND_HALF_EVEN));
            
    //
    ROUND_UP   
            
    //只要第2位后面存在大于0的小數,則第2位就+1

            System.out.println("-- ROUND_UP -- 只要第2位后面存在大于0的小數,則第2位就+1 --");
            System.out.println(round(
    12.34012, BigDecimal.ROUND_UP));//12.35   

            System.out.println(round(-12.34012, BigDecimal.ROUND_UP));//-12.35   
            
    //
    ROUND_DOWN   
            
    //
    與ROUND_UP相反   
            
    //直接舍棄第2位后面的所有小數   

            System.out.println("-- ROUND_DOWN -- 直接舍棄第2位后面的所有小數 --");
            System.out.println(round(
    12.3492, BigDecimal.ROUND_DOWN));//12.34   

            System.out.println(round(-12.3492, BigDecimal.ROUND_DOWN));//-12.34   
            
    //
    ROUND_CEILING   
            
    //
    如果數字>0 則和ROUND_UP作用一樣   
            
    //如果數字<0 則和ROUND_DOWN作用一樣   

            System.out.println("-- OUND_CEILING -- 如果數字>0 則和ROUND_UP作用一樣 如果數字<0 則和ROUND_DOWN作用一樣 --");
            System.out.println(round(
    12.34012, BigDecimal.ROUND_CEILING));//12.35   

            System.out.println(round(-12.3492, BigDecimal.ROUND_CEILING));//-12.34   
            
    //
    ROUND_FLOOR   
            
    //
    如果數字>0 則和ROUND_DOWN作用一樣   
            
    //如果數字<0 則和ROUND_UP作用一樣   

            System.out.println("-- ROUND_FLOOR -- 如果數字>0 則和ROUND_DOWN作用一樣 如果數字<0 則和ROUND_UP作用一樣 --");
            System.out.println(round(
    12.3492, BigDecimal.ROUND_FLOOR));//12.34   

            System.out.println(round(-12.34012, BigDecimal.ROUND_FLOOR));//-12.35   
            
    //
    ROUND_HALF_UP [這種方法最常用]   
            
    //
    如果第3位數字>=5,則第2位數字+1   
            
    //備注:只看第3位數字的值,不會考慮第3位之后的小數的   

            System.out.println("-- ROUND_HALF_UP -- 如果第3位數字>=5,則第2位數字+1 --");
            System.out.println(round(
    12.3452, BigDecimal.ROUND_HALF_UP));//12.35   

            System.out.println(round(12.34492, BigDecimal.ROUND_HALF_UP));//12.34   
            System.out.println(round(-12.3452, BigDecimal.ROUND_HALF_UP));//-12.35   
            System.out.println(round(-12.34492, BigDecimal.ROUND_HALF_UP));//-12.34   
            
    //
    ROUND_HALF_DOWN   
            
    //
    如果第3位數字>=5,則做ROUND_UP   
            
    //如果第3位數字<5,則做ROUND_DOWN   

            System.out.println("-- ROUND_HALF_DOWN -- 如果第3位數字>=5,則做ROUND_UP,如果第3位數字<5,則做ROUND_DOWN --");
            System.out.println(round(
    12.3452, BigDecimal.ROUND_HALF_DOWN));//12.35   

            System.out.println(round(12.34492, BigDecimal.ROUND_HALF_DOWN));//12.34   
            System.out.println(round(-12.3452, BigDecimal.ROUND_HALF_DOWN));//-12.35   
            System.out.println(round(-12.34492, BigDecimal.ROUND_HALF_DOWN));//-12.34   
            
    //
    ROUND_HALF_EVEN   
            
    //
    如果第3位是偶數,則做ROUND_HALF_DOWN   
            
    //如果第3位是奇數,則做ROUND_HALF_UP   

            System.out.println("-- ROUND_HALF_EVEN -- 如果第3位是偶數,則做ROUND_HALF_DOWN,如果第3位是奇數, 則做ROUND_HALF_UP --");
            System.out.println(round(
    12.3462, BigDecimal.ROUND_HALF_EVEN));//12.35   

            System.out.println(round(12.3452, BigDecimal.ROUND_HALF_EVEN));//12.35   
        }

    }


    再說說BigDecimal

    用于較小數的 BigDecimal

    從 JDK 1.3 起,Java 開發人員就有了另一種數值表示法來表示非整數: BigDecimalBigDecimal 是標準的類,在編譯器中不需要特殊支持,它可以表示任意精度的小數,并對它們進行計算。在內部,可以用任意精度任何范圍的值和一個換算因子來表示 BigDecimal ,換算因子表示左移小數點多少位,從而得到所期望范圍內的值。因此,用 BigDecimal 表示的數的形式為 unscaledValue*10 -scale

    用于加、減、乘和除的方法給 BigDecimal 值提供了算術運算。由于 BigDecimal 對象是不可變的,這些方法中的每一個都會產生新的 BigDecimal 對象。因此,因為創建對象的開銷, BigDecimal 不適合于大量的數學計算,但設計它的目的是用來精確地表示小數。如果您正在尋找一種能精確表示如貨幣量這樣的數值,則 BigDecimal 可以很好地勝任該任務。

    所有的 equals 方法都不能真正測試相等

    如浮點類型一樣, BigDecimal 也有一些令人奇怪的行為。尤其在使用 equals() 方法來檢測數值之間是否相等時要小心。 equals() 方法認為,兩個表示同一個數但換算值不同(例如, 100.00100.000 )的 BigDecimal 值是不相等的。然而, compareTo() 方法會認為這兩個數是相等的,所以在從數值上比較兩個 BigDecimal 值時,應該使用 compareTo() 而不是 equals()

    另外還有一些情形,任意精度的小數運算仍不能表示精確結果。例如, 1 除以 9 會產生無限循環的小數 .111111... 。出于這個原因,在進行除法運算時, BigDecimal 可以讓您顯式地控制舍入。 movePointLeft() 方法支持 10 的冪次方的精確除法。

    使用 BigDecimal 作為互換類型

    SQL-92 包括 DECIMAL 數據類型,它是用于表示定點小數的精確數字類型,它可以對小數進行基本的算術運算。一些 SQL 語言喜歡稱此類型為 NUMERIC 類型,其它一些 SQL 語言則引入了 MONEY 數據類型,MONEY 數據類型被定義為小數點右側帶有兩位的小數。

    如果希望將數字存儲到數據庫中的 DECIMAL 字段,或從 DECIMAL 字段檢索值,則如何確保精確地轉換該數字?您可能不希望使用由 JDBC PreparedStatementResultSet 類所提供的 setFloat()getFloat() 方法,因為浮點數與小數之間的轉換可能會喪失精確性。相反,請使用 PreparedStatementResultSetsetBigDecimal()getBigDecimal() 方法。

    對于 BigDecimal ,有幾個可用的構造函數。其中一個構造函數以雙精度浮點數作為輸入,另一個以整數和換算因子作為輸入,還有一個以小數的 String 表示作為輸入。要小心使用 BigDecimal(double) 構造函數,因為如果不了解它,會在計算過程中產生舍入誤差。請使用基于整數或 String 的構造函數。

    構造 BigDecimal 數

    對于 BigDecimal ,有幾個可用的構造函數。其中一個構造函數以雙精度浮點數作為輸入,另一個以整數和換算因子作為輸入,還有一個以小數的 String 表示作為輸入。要小心使用 BigDecimal(double) 構造函數,因為如果不了解它,會在計算過程中產生舍入誤差。請使用基于整數或 String 的構造函數。

    如果使用 BigDecimal(double) 構造函數不恰當,在傳遞給 JDBC setBigDecimal() 方法時,會造成似乎很奇怪的 JDBC 驅動程序中的異常。例如,考慮以下 JDBC 代碼,該代碼希望將數字 0.01 存儲到小數字段:

     PreparedStatement ps =
                connection.prepareStatement("INSERT INTO Foo SET name=?, value=?");
                ps.setString(1, "penny");
                ps.setBigDecimal(2, new BigDecimal(0.01));
                ps.executeUpdate();
                

    在執行這段似乎無害的代碼時會拋出一些令人迷惑不解的異常(這取決于具體的 JDBC 驅動程序),因為 0.01 的雙精度近似值會導致大的換算值,這可能會使 JDBC 驅動程序或數據庫感到迷惑。JDBC 驅動程序會產生異常,但可能不會說明代碼實際上錯在哪里,除非意識到二進制浮點數的局限性。相反,使用 BigDecimal("0.01")BigDecimal(1, 2) 構造 BigDecimal 來避免這類問題,因為這兩種方法都可以精確地表示小數。


    本文參考了一下文章,對這些作者表示感謝!

    Java 理論與實踐: 您的小數點到哪里去了?

    Java Double 精度問題總結

    JAVA對double或者float的浮點數精度計算控制方法

     

                                                                     THE END

    posted on 2010-02-22 13:59 小立飛刀 閱讀(5509) 評論(0)  編輯  收藏 所屬分類: Others
    <2010年2月>
    31123456
    78910111213
    14151617181920
    21222324252627
    28123456
    78910111213

    生存或毀滅,這是個必答之問題:是否應默默的忍受坎苛命運之無情打擊,還是應與深如大海之無涯苦難奮然為敵,并將其克服。此二抉擇,究竟是哪個較崇高?

    常用鏈接

    留言簿(12)

    隨筆分類(43)

    相冊

    收藏夾(7)

    朋友的博客

    電子資料

    搜索

    •  

    積分與排名

    • 積分 - 302642
    • 排名 - 192

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 野花香在线视频免费观看大全 | 麻豆91免费视频| 国产亚洲精品va在线| 免费人成在线观看69式小视频| 风间由美在线亚洲一区| 亚洲高清在线视频| 国产黄色片在线免费观看| 精品亚洲永久免费精品| 亚洲久悠悠色悠在线播放| 亚洲综合精品香蕉久久网| 国产黄色免费网站| 国产免费一区二区三区免费视频| 亚洲成人福利在线| 国产亚洲色婷婷久久99精品| 成人免费男女视频网站慢动作| 国产日韩AV免费无码一区二区| 亚洲欧美第一成人网站7777| 亚洲AV无码国产在丝袜线观看| 国产精品免费视频一区| h视频在线观看免费网站| 男人扒开添女人下部免费视频 | 三级网站在线免费观看| 亚洲色大成网站WWW国产| 久久精品国产亚洲AV无码麻豆| 亚洲 另类 无码 在线| 成人免费视频69| 日本人成在线视频免费播放| 女人裸身j部免费视频无遮挡| 亚洲乱码一区av春药高潮| 亚洲成AV人在线观看天堂无码| 国产免费久久精品| 毛片免费全部播放一级| 一级毛片免费不卡在线| 国产99久久久久久免费看| 色偷偷噜噜噜亚洲男人| 亚洲人成人77777在线播放| 亚洲免费精彩视频在线观看| 亚洲色图综合在线| 亚洲国产成人久久综合区| 免费鲁丝片一级在线观看| 成人免费毛片内射美女-百度|