Java中double相減精度的問題,和解決方法


問題原因原帖1 

解決方法:

使用BigDecimal方法來解決。

BigDecimal原理是什么?為什么它就沒事?原理很簡單。BigDecimal是不可變的,可以用來表示任意精度的帶符號十進制數。double的問題是從小數點轉換到二進制丟失精度,二進制丟失精度。BigDecimal在處理的時候把十進制小數擴大N倍讓它在整數上進行計算,並保留相應的精度信息。至於BigDecimal是怎么保存的可以翻閱一下源代碼。

/**
 * double的計算不精確,會有類似0.0000000000000002的誤差,正確的方法是使用BigDecimal或者用整型
 * 整型地方法適合於貨幣精度已知的情況,比如12.11+1.10轉成1211+110計算,最后再/100即可
 * 以下是摘抄的BigDecimal方法:
 */
 public class DoubleUtils implements Serializable {
     private static final long serialVersionUID = -3345205828566485102L;
     // 默認除法運算精度
     private static final Integer DEF_DIV_SCALE = 2;

     /**
      * 提供精確的加法運算。
     *
      * @param value1 被加數
      * @param value2 加數
    * @return 兩個參數的和
    */
    public static Double add(Double value1, Double value2) {
         BigDecimal b1 = new BigDecimal(Double.toString(value1));
         BigDecimal b2 = new BigDecimal(Double.toString(value2));
         return b1.add(b2).doubleValue();
    }

    /**
      * 提供精確的減法運算。
      *
      * @param value1 被減數
      * @param value2 減數
      * @return 兩個參數的差
      */
     public static double sub(Double value1, Double value2) {
         BigDecimal b1 = new BigDecimal(Double.toString(value1));
        BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精確的乘法運算。
     *
      * @param value1 被乘數
      * @param value2 乘數
     * @return 兩個參數的積
     */
     public static Double mul(Double value1, Double value2) {
        BigDecimal b1 = new BigDecimal(Double.toString(value1));
         BigDecimal b2 = new BigDecimal(Double.toString(value2));
        return b1.multiply(b2).doubleValue();
   }
    /**
    * 提供(相對)精確的除法運算,當發生除不盡的情況時, 精確到小數點以后10位,以后的數字四舍五入。
    *
    * @param dividend 被除數
    * @param divisor  除數
    * @return 兩個參數的商
    */
     public static Double divide(Double dividend, Double divisor) {
        return divide(dividend, divisor, DEF_DIV_SCALE);
    }

     /**
    * 提供(相對)精確的除法運算。 當發生除不盡的情況時,由scale參數指定精度,以后的數字四舍五入。
    *
    * @param dividend 被除數
    * @param divisor  除數
    * @param scale    表示表示需要精確到小數點以后幾位。
    * @return 兩個參數的商
    */
     public static Double divide(Double dividend, Double divisor, Integer scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
       BigDecimal b1 = new BigDecimal(Double.toString(dividend));
      BigDecimal b2 = new BigDecimal(Double.toString(divisor));
         return b1.divide(b2, scale,RoundingMode.HALF_UP).doubleValue();
    }

 /**
   * 提供指定數值的(精確)小數位四舍五入處理。
   *
   * @param value 需要四舍五入的數字
   * @param scale 小數點后保留幾位
   * @return 四舍五入后的結果
   */
    public static double round(double value,int scale){
         if(scale<0){
           throw new IllegalArgumentException("The scale must be a positive integer or zero");
         }
         BigDecimal b = new BigDecimal(Double.toString(value));
       BigDecimal one = new BigDecimal("1");
        return b.divide(one,scale, RoundingMode.HALF_UP).doubleValue();
     }
 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM