最近在看項目中的各種計算,由于是金融方面的項目,觸及到日化,年化,利息,債轉這些和錢有關的計算很多,其中全部通過BigDecimal類進行的運算,之前觸及到的計算基本都用+、-、*、/等算術運算符直接進行數學運算,數據類型1般用double就可以解決問題,但是如果要求完全精度時double就不適合了,由于double是在廣域數值范圍上提供較為精確的快速近似計算(只能處理16位有效數)。
BigDecimal是Java在java.math包中提供的API類,主要用來對超過16位有效位的數進行精確的運算。雙精度浮點型變量double可以處理16位有效數。在實際利用中,需要對更大或更小的數進行運算和處理。float和double只能用來做科學計算或是工程計算,在商業計算中要用java.math.BigDecimal。
BigDecimal所創建的是對象,我們不能使用傳統的+、-、*、/等算術運算符直接對其對象進行數學運算,而必須調用其相對應的方法。方法中的參數也必須是BigDecimal的對象。下面來看BigDecimal的構造方法。
BigDecimal(int)創建1個具有參數所指定整數值的對象。
BigDecimal(double)創建1個具有參數所指定雙精度值的對象。
BigDecimal(long)創建1個具有參數所指定長整數值的對象。
BigDecimal(String)創建1個具有參數所指定以字符串表示的數值的對象。
這里需要注意的是double類型的,先看1個實例:
輸出結果:
1、這里我們注意到參數為double類型是,構造的BigDecimal值實際上等于1.100000000000000088817841970012523233890533447265625,而不是1.1,這是由于1.1沒法準確地表示為double(或說對該情況,不能表示為任何有限長度的2進制小數)。
2、參數為String類型構造的BigDecimal值正好等于原值1.1。因此,在我們構造BigDecimal值時通常選擇參數為String類型的構造方法。
3、當double 必須用作BigDecimal的參數時,可以先使用Double.toString(double)方法將double轉換為String,然后使用BigDecimal(String)構造方法。再使用BigDecimal.valueOf(double)方法獲得值。
加減乘除最基本的運算
BigDecimal add(BigDecimal augend) 加法運算
BigDecimal subtract(BigDecimal subtrahend) 減法運算
BigDecimal multiply(BigDecimal multiplicand) 乘法運算
BigDecimal divide(BigDecimal divisor) 除法運算
由于尋求高精度,我們使用BigDecimal,但是在進行帶除法的運算時,并且結果需要保存有效位數的時,可能會出現精度問題。那甚么時候會出現呢?
我們知道10除3是永久除不盡的,并且結果我們需要進行格式化(保存有效位數)
BigDecimal對象的精度沒有限制。對除不盡的除法運算,比如10/3,divide方法將會拋出 java.lang.ArithmeticException毛病,所以除法運算要盡可能使用divide(BigDecimal d, int scale, int roundMode)指定標度和保存模式來避免異常。
scale,標度,小數點保存的位數
roundMode,保存模式
BigDecimal.ROUND_DOWN:直接丟掉標度之外的小數
BigDecimal.ROUND_UP:不管舍棄的小數是幾,都進1
BigDecimal.ROUND_HALF_UP:最多見的4舍5入
還有其他的模式,可以直接去源碼里看。
來看實例計算:
value: 3.3333333333
value: 9.9999999999
由于第1步的除法指定了標度和保存模式,我們得到的是1個近似值,已丟失了精度,在進行后續的運算中,精度已沒法保證,如何解決這類問題?應當把除法運算放在全部運算的最后,以減小除法帶來的精度問題。
商業計算對錢最敏感,1分1毫平時看來很小,但是放在million,billion中,every
hundred損失a cent,結果也是巨大的。學習亦是如此,每天學習1分,1年后取得的改變也是巨大的。