最近在作支付相關模塊的業務,數據庫字段卻使用的是double類型,其實也行,只要計算不在sql語句中進行,也是沒有問題的。java
預先的類屬性設置的是Double類型,本身算的時候發現小數相加會出現損失精度的狀況程序員
以下情形sql
@Test public void testDouble(){ Double [] arr = {39.9d,50d,198d,39.9d}; Double verify = 0d; for (Double aDouble : arr) { verify += aDouble ; } System.out.println(verify); }
輸出的結果是:327.79999999999995 理應爲:328數據庫
待着疑惑試了下js編程
一看是一個效果,精度都會缺失。百度了下,解釋以下編程語言
實數符號位 指數符號位 指數位 有效數位測試
可是,在將十進制浮點數轉換爲二進制浮點數時,小數的二進制有時也是不可能精確的,就如同十進制不能準確表示1/3,二進制也沒法準確表示1/10,而double類型存儲尾數部分最多隻能存儲52位,因而,計算機在存儲該浮點型數據時,便出現了精度丟失。spa
例如,11.9的內存存儲大約爲:1011. 1110011001100110011001100...翻譯
而在進行浮點類數據計算的時候,浮點參與計算,會左移或右移n位,直到小數點移動到第一個有效數字的右邊。因而11.9在轉化爲二進制後 小數點左移3位,就獲得1. 011 11100110011001100110(精度丟失2)code
因而最終浮點型運算出現了精度丟失偏差。
解決方式,java中可使用 BigDecimal 來解決
@Test public void test3(){ System.out.println(0.11+2001299.32);//非精確的輸出
BigDecimal bigDecimal1 = new BigDecimal(Double.toString(0.11)); BigDecimal bigDecimal2 = new BigDecimal(Double.toString(2001299.32)); System.out.println(bigDecimal1.add(bigDecimal2));//精確的輸出
}
這種方式能夠解決,而且很完美,可是還有一種方式比較容易些,畢竟是金額,小數位只有兩位,能夠先將其擴大100倍,再進行計算,計算完畢以後再除100,也能夠解決(這麼不要臉的方式也只有我這麼low的程序員使用了),慚愧,出錯了。
在計算的過程總遇到double轉int的狀況,總結了下實現的方式
Double d = 1.7d; @Test public void test1(){ // 這樣會報錯,由於double轉換爲字符串以後有. System.out.println(Integer.parseInt(d.toString())); } @Test public void test2_1(){ // double 類型能夠直接轉爲int類型 double dd = 1.1; int ddd = (int)dd; System.out.println(ddd); } @Test public void test2_2(){ // 能夠經過強轉進行轉換,Double是包裝類,不能直接進行強轉,能夠拆箱以後再次強轉。 int aa = (int)(Double.parseDouble(d.toString())); System.out.println(aa); } @Test public void test3(){ // 這種方式最爲簡單 System.out.println(d.intValue()); } @Test public void test4(){ DecimalFormat format1 = new DecimalFormat("#"); String s = format1.format(d); System.out.println(s); } @Test public void test5(){ DecimalFormat format1 = new DecimalFormat("#.#"); String s = format1.format(1.35); System.out.println(s); } @Test public void test6(){ DecimalFormat format1 = new DecimalFormat("0.000"); String s = format1.format(1.35); System.out.println(s); }
DecimalFormat 要四捨五入須要加上 setRoundingMode(RoundingMode.HALF_UP); 網上是這麼說的,可是本身測試默認就會四捨五入
特殊字符說明
「0」 指定位置不存在數字則顯示爲0 123.123 ->0000.0000 ->0123.1230
「#」 指定位置不存在數字則不顯示 123.123 -> ####.#### ->123.123
「.」 小數點
「%」 會將結果數字乘以100 後面再加上% 123.123 ->#.00->1.3212%
嗯,就這麼個坑了。