double 轉 BigDecimal 精度問題
請看圖:
//double 轉 BigDecimal 精度測試 @Test public void a (){ Double Dou = 5.56; BigDecimal bigDou1 = new BigDecimal(Dou); BigDecimal bigDou2 = BigDecimal.valueOf(Dou); log.info("Double轉BigDecimal,使用構造方法轉化="+bigDou1);//5.55999999999999960920149533194489777088165283203125 log.info("Double轉BigDecimal,使用字串形式轉化="+bigDou2);//5.56 }
很明顯,經過 double 轉 BigDecimal 後,我們最初的值已經發生變化,所以通常我們在做型別轉換的時候推薦使用 BigDecimal.valueOf(...);
分析:JDK1.8 原始碼
BigDecimal bigDou1 = new BigDecimal(Dou);
這個轉換結果是double的二進位制浮點值的精確十進位制表示,其值得結果不是我們可以預測的,如上測試類,經過型別轉換:5.56變成了5.55999999999999960920149533194489777088165283203125。是因為轉化過程預設使用了精度和舍入模式:
public BigDecimal(double val, MathContext mc) {}; 舍入模式為:public final static int ROUND_HALF_UP =4;也是一種四捨五入,官方解釋:該四捨五入模式向“最近鄰居”轉彎,除非兩個鄰居都是等距的,在這種情況下是圓括弧的。
BigDecimal bigDou2 = BigDecimal.valueOf(Dou);
原始碼:
public static BigDecimal valueOf(double val) {
return new BigDecimal(Double.toString(val));
}
使用double通過所提供的規範的字串表示Double.toString(double)方法。呼叫BigDecimal bigDou2 = BigDecimal.valueOf("String");此時5.56=5.56.所以進行型別轉換推薦此方法。
另外:如果資料庫儲存,可以直接寫入 double。
INSERT INTO statistic_info (`id`,`amount`) VALUES (#{bean.id},#{bean.amountDouble});