金融系統中的金額計算及存儲方式,你知道嗎?

經典的精度丟失問題

Java中的類型 float 、 double 用來做計算會有精度丟失問題,比如下面這種情況

<code>double d1 = 0.09;
double d2 = 0.02;
double d3 = d1 - d2;
System.out.println(d3);
float f1 = 0.09F;
float f2 = 0.02F;
float f3 = f1 - f2;
System.out.println(f3);/<code>

讓我們口算一下上面計算的結果:

no no no

正確答案是:

<code>0.07
0.07
0.06999999999999999
0.07000001/<code>

為什麼會產生這種情況?

金融系統中的金額計算及存儲方式,你知道嗎?

浮點數可能丟失精度,因為浮點十進制數通常沒有完全相同的二進制的表示形式,這是CPU所採用的浮點數據表示形式的副作用。為此,可能會有一些精度丟失,並且一些浮點運算可能會產生未知的結果。

解決辦法

BigDecimal 適合更精度的運算,也提供了豐富的操作符類型,小數位控制,四捨五入規則等。

不過,使用 BigDecimal 不當也有精度丟失的情況,如double的構造方法:

<code>BigDecimal(double val)/<code>

再來看這個示例:

<code>double f1 = 0.09;
double f2 = 0.02;
BigDecimal f3 =
       new BigDecimal(f1).subtract(
       new BigDecimal(f2));
System.out.println(f3);/<code>

計算結果:

<code>0.0699999999999999962529972918900966760702431201934814453125/<code>

這個精度丟失就更恐怖了......怎麼解決呢?

一般使用 BigDecimal 進行運算的時候都會使用String的構造方法:

<code>BigDecimal(String val) 

double f1 = 0.09;
double f2 = 0.02;
BigDecimal f3 =
       new BigDecimal(String.valueOf(f1)).subtract(
       new BigDecimal(String.valueOf(f2)));
System.out.println(f3);/<code>

加減乘除

下面是使用 BigDecimal 運算的時候的加減乘除

<code>//加法
BigDecimal f1=new BigDecimal("2.22");
BigDecimal f2=new BigDecimal("1.22");
System.out.println(f1.add(f2));
//減法
System.out.println(f1.subtract(f2));
//乘法
System.out.println(f1.multiply(f2));
//除法
//在除法中要注意,BigDecimal做除法的時候一定要在divide方法中傳遞第二個參數,定義精確到小數點
//後幾位,否則在不整除的情況下,結果是無限循環小數時,就會拋出以上異常。
//解決方法:f1.divide(f2, 2, BigDecimal.ROUND_HALF_UP);
System.out.println(f1.divide(f2,2, BigDecimal.ROUND_HALF_UP));/<code>

相關閱讀:

總結

金額運算儘量使用 BigDecimal(String val) 進行運算。

數據庫存儲金額,一般有整型和浮點型兩種存儲方式。如果是有匯率轉換的,建議使用浮點數decimal進行存儲,可以靈活的控制精度,decimal直接對應 java 類型 BigDecimal 。當然,用整數存儲分這種形式也可以,轉賬的時候單位為元而如果忘了轉換分為元,那就悲劇了。

ok,就到這裡,喜歡的朋友記得點個贊or(and)關注or(and)收藏or(and)轉發.....

金融系統中的金額計算及存儲方式,你知道嗎?


分享到:


相關文章: