金融系统中正确的金额计算及存储方式
轉(zhuǎn)載自?金融系統(tǒng)中正確的金額計算及存儲方式
經(jīng)典的精度丟失問題
Java中的類型float、double用來做計算會有精度丟失問題,下面來看下面的示例。
public static void main(String[] args) {test1();test2(); } private static void test1() {double totalAmount = 0.09;double feeAmount = 0.02;double tradeAmount = totalAmount - feeAmount;System.out.println(tradeAmount); }上面的程序輸出結(jié)果是多少?
0.07?非也!
正確的結(jié)果是:
0.06999999999999999為什么是這樣?
浮點數(shù)可能丟失精度,浮點十進制數(shù)通常沒有完全相同的二進制的表示形式,這是CPU所采用的浮點數(shù)據(jù)表示形式的副作用。為此,可能會有一些精度丟失,并且一些浮點運算可能會產(chǎn)生未知的結(jié)果。
浮點運算很少是精確的,只要是超過精度能表示的范圍就會產(chǎn)生誤差。所以,在使用float、double作精確運算的時候一定要特別小心,除非能容忍精度丟失,不然產(chǎn)生的誤差也是會造成雙方對賬不一致的結(jié)果。
怎么解決
在《Effective Java》這本書中也提到這個原則,float和double只能用來做科學(xué)計算或者是工程計算,在商業(yè)計算中我們要用 java.math.BigDecimal。
BigDecimal適合更精度的運算,也提供了豐富的操作符類型,小數(shù)位控制,四舍五入規(guī)則等。
不過,使用BigDecimal不當(dāng)也有精度丟失的情況,如double的構(gòu)造方法:
BigDecimal(double val)再來看這個示例:
private static void test2() {double totalAmount = 0.09;double feeAmount = 0.02;BigDecimal tradeAmount = new BigDecimal(totalAmount).subtract(new BigDecimal(feeAmount));System.out.println(tradeAmount); }輸出:
0.0699999999999999962529972918900966760702431201934814453125這個精度就更恐怖了。。
所以,一定要使用String的構(gòu)造方法:
BigDecimal(String val) private static void test3() {double totalAmount = 0.09;double feeAmount = 0.02;BigDecimal tradeAmount = new BigDecimal(String.valueOf(totalAmount)).subtract(new BigDecimal(String.valueOf(feeAmount)));System.out.println(tradeAmount); }總結(jié)
金額運算盡量使用BigDecimal(String val)進行運算。
數(shù)據(jù)庫存儲金額,一般有整型和浮點型兩種存儲方式。如果是有匯率轉(zhuǎn)換的,建議使用浮點數(shù)decimal進行存儲,可以靈活的控制精度,decimal直接對應(yīng)java類型BigDecimal。當(dāng)然,用整數(shù)存儲分這種形式也可以,轉(zhuǎn)賬的時候單位為元而如果忘了轉(zhuǎn)換分為元,那就悲劇了。
總結(jié)
以上是生活随笔為你收集整理的金融系统中正确的金额计算及存储方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么笔记本适合用于做数模建模?
- 下一篇: 缓存雪崩,缓存穿透,缓存预热,缓存热备都