天天看點

BigDecimal代替浮點數精确計算用法簡介

浮點數

浮點數是屬于有理數中某特定子集的數的數字表示,在計算機中用以近似表示任意某個實數。具體的說,這個實數由一個整數或定點數(即尾數)乘以某個基數(計算機中通常是2)的整數次幂得到,這種表示方法類似于基數為10的科學計數法。

浮點計算是指浮點數參與的運算,這種運算通常伴随着因為無法精确表示而進行的近似或舍入。

一個浮點數a由兩個數m和e來表示:a = m × b^e。在任意一個這樣的系統中,我們選擇一個基數b(記數系統的基)和精度p(即使用多少位來存儲)。m(即尾數)是形如±d.ddd...ddd的p位數(每一位是一個介于0到b-1之間的整數,包括0和b-1)。如果m的第一位是非0整數,m稱作規格化的。有一些描述使用一個單獨的符号位(s 代表+或者-)來表示正負,這樣m必須是正的。e是指數。

bigdecimal

在java中,float聲明的變量是單精度浮點數,double聲明的變量是雙精度浮點數,顧名思義就是double型的實體占用記憶體空間是float的兩倍。float是4個位元組而double是8個位元組。float和double類型的資料,無法精确表示計算結果,這是由于float和double是不精确的計算。大家可以通過下面代碼可以看出來:

運作的結果為:

0.060000000000000005

0.5800000000000001

401.49999999999994

1.2329999999999999

要想獲得理想的結果,我們可以考慮使用bigdecimal來獲得更精确的計算:

bigdecimal提供了多個構造函數,和浮點數有關的有:

bigdecimal(double val)  translates a double into a bigdecimal.

bigdecimal(string val) translates the string repre sentation of a bigdecimal into a bigdecimal.

但是用double參數來建立對象得到不精确的值,隻有通過string來建立對象才是最準确的。

例如:

bigdecimal data1=new bigdecimal(0.05);

system.out.println(data1.tostring());

bigdecimal data2=new bigdecimal("0.05");

system.out.println(data2.tostring());

得到結果:

0.05000000000000000277555756156289135105907917022705078125

是以,我們最終需要使用string來建立對象,這樣得到的結果才是最精确的。另外,如果是double數,我們還可以使用:bigdecimal.valueof(double val),原因很簡單,其jdk源碼如下所示:

最後需要說明的是:bigdecimal的加減乘除其實最終都傳回的是一個新的bigdecimal對象,因為bigdecimal是不可變的(immutable)的,在進行每一步運算時,都會産生一個新的對象,是以a.add(b);雖然做了加法操作,但是a并沒有儲存加操作後的值,正确的用法應該是a=a.add(b)。

參考文章:

<a href="http://swiftlet.net/archives/798" target="_blank">http://swiftlet.net/archives/798</a>