java小數運算,內附現成的工具類。不能用double和float,要用decimal
https://www.cnblogs.com/xujishou/p/7491932.h
為什麼會出現這個問題呢,就這是java和其它計算機語言都會出現的問題,下面我們分析一下為什麼會出現這個問題:
float和double型別主要是為了科學計算和工程計算而設計的。他們執行二進位制浮點運算,這是為了在廣泛的數字範圍上提供較為精確的快速近似計算而精心設計的。然而,它們並沒有提供完全精確的結果,所以我們不應該用於精確計算的場合。float和double型別尤其不適合用於貨幣運算,因為要讓一個float或double精確的表示0.1或者10的任何其他負數次方值是不可能的(其實道理很簡單,十進位制系統中能不能準確表示出1/3呢?同樣二進位制系統也無法準確表示1/10)。
浮點運算很少是精確的,只要是超過精度能表示的範圍就會產生誤差。往往產生誤差不是因為數的大小,而是因為數的精度。因此,產生的結果接近但不等於想要的結果。尤其在使用 float 和 double 作精確運算的時候要特別小心。
現在我們就詳細剖析一下浮點型運算為什麼會造成精度丟失?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
5 / 2 = 2 餘 1
|
解決方法
使用BigDecmal,而且需要在構造引數使用String型別。
在《Effective Java》這本書中就給出了一個解決方法。該書中也指出,float和double只能用來做科學計算或者是工程計算,在商業計算等精確計算中,我們要用java.math.BigDecimal。
BigDecimal類有4個構造方法,我們只關心對我們解決浮點型資料進行精確計算有用的方法,即
BigDecimal(double value) // 將double型資料轉換成BigDecimal型資料
思路很簡單,我們先通過BigDecimal(double value)方法,將double型資料轉換成BigDecimal資料,然後就可以正常進行精確計算了。等計算完畢後,我們可以對結果做一些處理,比如 對除不盡的結果可以進行四捨五入。最後,再把結果由BigDecimal型資料轉換回double型資料。
這個思路很正確,但是如果你仔細看看API裡關於BigDecimal的詳細說明,你就會知道,如果需要精確計算,我們不能直接用double,而非要用 String來構造BigDecimal不可!所以,我們又開始關心BigDecimal類的另一個方法,即能夠幫助我們正確完成精確計算的 BigDecimal(String value)方法。
// BigDecimal(String value)能夠將String型資料轉換成BigDecimal型資料
那麼問題來了,想像一下吧,如果我們要做一個浮點型資料的加法運算,需要先將兩個浮點數轉為String型資料,然後用 BigDecimal(String value)構造成BigDecimal,之後要在其中一個上呼叫add方法,傳入另一個作為引數,然後把運算的結果(BigDecimal)再轉換為浮 點數。如果每次做浮點型資料的計算都要如此,你能夠忍受這麼煩瑣的過程嗎?至少我不能。所以最好的辦法,就是寫一個類,在類中完成這些繁瑣的轉換過程。這 樣,在我們需要進行浮點型資料計算的時候,只要呼叫這個類就可以了。網上已經有高手為我們提供了一個工具類Arith來完成這些轉換操作。它提供以下靜態 方法,可以完成浮點型資料的加減乘除運算和對其結果進行四捨五入的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
|
附上Arith的原始碼,大家只要把它編譯儲存好,要進行浮點數計算的時候,在你的源程式中匯入Arith類就可以使用以上靜態方法來進行浮點數的精確計算了