Java中double float 類型的數據(小數)在作計算的時候要注意的

  以前,只是聽說過,Java裏面有些個類型,在計算的時候,是不能想當然的,因爲,計算機的實現法和你自己的想法是不一樣的。當時,沒怎麼在意,後來,還真聽一個哥們說,他把錢給算錯了。既然遇到了,我就稍微做個筆記,以後遇到類似問題,自己也好有個印象,
  先看奇葩現象。

private static void testDouble() {  
    Double d = 0.81d;  
    System.out.println(d);  
    PrintUtil.divideLine();  
    System.out.println("0.05 + 0.01 = " + (0.05 + 0.01));//0.060000000000000005  
    System.out.println("1.0 - 0.42 = " + (1.0 - 0.42));//0.5800000000000001  
    System.out.println("4.015 * 100 = " + (4.015 * 100));//401.49999999999994  
    System.out.println("123.3 / 100 = " + (123.3 / 100));//1.2329999999999999  
    System.out.println(new DecimalFormat("0.00").format(4.025d));//4.03 四捨五入  
}  

  就簡單在意下,上面的幾個double類型的數據的計算結果就好啦。其他都是寫打印個分界符啥的代碼。我弄個工具類,使用方便些。
可以看到,這些 double的計算,果然跟想象的有點不一樣。
就像,他們說的4.999999999999999在計算機看來,可買不到,標價爲5。0000塊錢的東西。那就出問題啦。

  這個時候,就要用到一個叫 BigDecimal 的類啦。
  下面看一個工具類的代碼

package com.lxk.util;  

import java.io.Serializable;  
import java.math.BigDecimal;  
import java.math.RoundingMode;  

/** 
 * 精確計算 double and float 
 * Created by lxk on 2017/9/27 
 */  
public class DoubleUtil 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();  
    }  
}  

  下面是,這個工具類的實際使用代碼,爲了操作對比方便,我就不嫌囉嗦的把代碼再複製一遍吧

/** 
 * double的一些計算奇葩現象,試驗一把,就印象深刻啦。 
 */  
private static void testDouble() {  
    Double d = 0.81d;  
    System.out.println(d);  
    PrintUtil.divideLine();  
    System.out.println("0.05 + 0.01 = " + (0.05 + 0.01));//0.060000000000000005  
    System.out.println("1.0 - 0.42 = " + (1.0 - 0.42));//0.5800000000000001  
    System.out.println("4.015 * 100 = " + (4.015 * 100));//401.49999999999994  
    System.out.println("123.3 / 100 = " + (123.3 / 100));//1.2329999999999999  
    System.out.println(new DecimalFormat("0.00").format(4.025d));//4.03 四捨五入  
}  

/** 
 * 精確計算 
 */  
private static void testDoubleExact() {  
    System.out.println("0.05 + 0.01 = " + DoubleUtil.add(0.05, 0.01));  
    System.out.println("1.0 - 0.42 = " + DoubleUtil.sub(1.0, 0.42));  
    System.out.println("4.015 * 100 = " + DoubleUtil.mul(4.015, 100d));  
    System.out.println("123.3 / 100 = " + DoubleUtil.divide(123.3, 100d));//保留兩位  
    System.out.println("123.3 / 100 = " + DoubleUtil.divide(123.3, 100d, 3));//保留三位  
    System.out.println(DoubleUtil.round(4.025d, 2));  
}  

  這就省略了main方法啦。
  下面看上述代碼的運行結果。
這裏寫圖片描述
  這個不是什麼高科技,但是得有個印象,知道有這麼個問題存在,不然,那就真得跟我那哥們一樣,等到真正出問題啦,才知道,錢這麼算是有大問題的。
  上面的事Java代碼裏面的,
  下面看JavaScript裏面的。
這裏寫圖片描述



  這個世界上沒有知識是學不會的,不是嗎?如果一開始學不會,就可以把問題細化分解,然後學習更基本的知識。最後,所有問題都能變得和1+1=2一樣簡單,我們需要的只是時間。好了,最後給大家推薦一個學習Java的好網站JAVA自學網站–how2j.cn

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章