Java中2減1.1等於幾?

在Java中有一個奇怪的現象,我們編寫代碼2-1.1,原本以爲結果是非常明顯的0.9,但答案卻讓人大吃一驚,如圖:

原因在於:Java基本數據類型中的float、double類型的實質是浮點數,浮點數不能存儲精確的數據,這樣的話,浮點數在進行計算的時候,計算結果就不是精確的值。所以這裏得出經驗,在實際開發中,我們在對數值進行計算的時候,應儘量避免使用Java的+ - * / 等運算符,因爲容易出現損失精度的問題,導致最終的計算結果錯誤。

尤其是在電商平臺中都是杜絕使用此種計算方式的,因爲由於這種計算導致金額出現的誤差,所帶來的損失是無法估量的,也許就因爲差一分錢,導致報表計算錯誤,客戶賬單對不上,都會帶來大麻煩。所以我們有必要找到一種正確的計算方法。

Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數進行精確的運算。雙精度浮點型變量double可以處理16位有效數。在實際應用中,需要對更大或者更小的數進行運算和處理。float和double只能用來做科學計算或者是工程計算,在商業計算中要用java.math.BigDecimal。BigDecimal所創建的是對象,我們不能使用傳統的+、-、*、/等算術運算符直接對其對象進行數學運算,而必須調用其相對應的方法。

1、加法

2、減法

3、乘法

在上述的截圖中,會發現我們在做運算之前,都會將double值轉化爲String值,儘管BigDecimal提供了多種構造方法,也是支持傳入double值的,但這裏我們並不推薦。因爲傳入double值是容易出問題的,如圖:

a)參數類型爲double的構造方法的結果有一定的不可預知性。有人可能認爲在Java中寫入

newBigDecimal(0.1)所創建的BigDecimal正好等於 0.1(非標度值 1,其標度爲 1),但是它實際上等於0.1000000000000000055511151231257827021181583404541015625。這是因爲0.1無法準確地表示爲 double(或者說對於該情況,不能表示爲任何有限長度的二進制小數)。這樣,傳入到構造方法的值不會正好等於 0.1(雖然表面上等於該值)。

b)另一方面,String 構造方法是完全可預知的:寫入 newBigDecimal("0.1") 將創建一個 BigDecimal,它正好等於預期的 0.1。因此,比較而言,通常建議優先使用String構造方法。

c)當double必須用作BigDecimal的源時,請注意,此構造方法提供了一個準確轉換;它不提供與以下操作相同的結果:先使用Double.toString(double)方法,然後使用BigDecimal(String)構造方法。將double轉換爲String,也可以使用String的static方法:String.valueOf(double)。

4、除法

在使用除法時,我們發現divide方法中,我們多傳入了幾個參數。如果對於可以除盡的數不傳入這兩個參數也是沒有問題的,但如果我們使用100除以3會出現什麼問題呢?

我們發現報錯了,原因在於:通過BigDecimal的divide方法進行除法時當不整除,出現無限循環小數時,就會拋異常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 所以不管能不能除盡,我們都要防患於未然告訴運算器我們除不盡的方案是什麼。

BigDecimal已經幫助我們定義好了舍入模式,只有在作除法運算或四捨五入時纔用到舍入模式。如下圖:

這麼多的四捨五入模式,我們在實際開發中應該使用那種呢,這個還是要分情況的。我倒是建議使用UNNECESSARY這種模式:計算結果是精確的,不需要四捨五入,那你可能會說這樣不就有問題了嗎?彆着急,待計算完成後我們再單獨對結果進行四捨五入?爲什麼要這樣呢?因爲我們不能保證我們的程序中只存在一次計算,如果我們有一個公式要連續對數值進行乘法和除法,每次都四捨五入,那計算結果纔會有問題,但如果我們只對最終的結果值四捨五入就沒有問題了,因爲多數在保存的時候,數據庫都要求保留兩位小數。首先我們來看下不同的模式下計算的結果值有什麼差異?

在UNNECESSARY的時候最爲精確。因爲其保留的小數也最多。具體我們可以打開源代碼自己看下原因。那最終我們如何將數值保留兩位小數呢?

例如:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章