2011-12-28 100 views
3

基本上,我不明白爲什麼當4.35 * 100 = 435.0被轉換爲435的int時,下面的代碼會輸出434,對嗎?Java舍入問題

這是什麼簡單的解釋,這是一個經常出現的問題?

你會如何解決這個問題?

public class RoundOffDemo { 
    public static void main(String[] args) { 
     double price = 4.35; 
     int cents = (int) (100 * price); // Should be 435 
     System.out.println(cents); // Prints 434! 
    } 
} 
+0

可能的重複[浮點運算不能在Java中產生精確的結果](http://stackoverflow.com/questions/1661273/floating-point-arithmetic-not-產生不精確的-成果在-java的)。還有至少一百個其他問題。 – dan04 2011-12-28 23:46:22

回答

7

問題是4.35不能用二進制精確表示。所以4.35 * 100並不完全是435.0。 (二進制中的每個分數都是2的反冪的和,所有這些都是終止小數。不幸的是,0.35十進制有一個非終止二進制擴展。因此4.35更像4.349999 ... x(其中x是某種東西除此之外,一切都爲零,由機器的浮點數的有限表示形式提供)。整數截斷然後產生434.你可以使用Math.round()來避免這個問題

+0

另外,我想Math.rint()更適合在這種情況下使用(轉換爲int)。 – 4ndrew 2011-12-28 17:11:45

+0

@ 4ndrew - 也許如此。人們也可以將參數轉換爲「float」,以便「round」返回「int」。 (儘管對於OP所使用的數字,使用'float'開始而不是'double'可能是最好的選擇。) – 2011-12-28 17:19:37

+2

「真實世界」中的一個很好的例子是1/3,不能準確表示小數。如果計算機使用十進制而不是二進制,則1/3 * 3將爲0.9999999,而不是1.0。 – user949300 2011-12-28 18:36:26

-1
  1. 不要在Java中使用雙/浮點進行浮點運算,使用的BigDecimal代替。這是因爲Java不能精確地表示浮點。

  2. 對於臨時變量總是使用BigDecimal,這將在未來的計算中處理/參與。只有在您想將它們保存到數據庫中時纔將值轉換爲float/double。

+1

我不會使用BigDecimal作爲萬能藥。它一般不能真正解決舍入問題。例如,如果你劃分並且結果不能精確地用十進制表示,那麼要麼你需要指定舍入模式,否則你會得到一個異常。但是通過指定舍入模式,您又回到了問題中:即使使用BigDecimal,3 *(4/3)!= 4. – 2011-12-28 17:00:27

+1

浮點數的不精確表示並不是繼承給Java的問題。而是運行在二進制體系結構上的計算機固有的問題。 – Perception 2011-12-28 17:19:27

0

這是浮點運算的結果。不是一個舍入函數,而是@Ted指出的截斷。

由於您正在處理金錢(從您的變量名稱中可以看出),請改用BigDecimal。

例如 -

double d = 4.35; 
BigDecimal bd = BigDecimal.valueOf(d); 
bd = bd.multiply(new BigDecimal(100)); 
+1

這並不解決問題; 'd'已經不是4.35,所以'bd'只是將這個舍入誤差向前傳遞。 – 2011-12-28 18:42:35

+0

@Ted - 我實際上已經試過了,並確保它在發佈代碼之前工作。 BigDecimal.valueOf(d)'使用'Double.toString(d)'並始終產生相同的輸出。我在做一個假設,我不應該在這裏? – Kal 2011-12-28 19:27:56

+1

在這個地方肯定還有別的東西(可能是四捨五入的)。十進制4.35是二進制100.0(1011)。它不能完全以浮點表示。 – 2011-12-28 19:43:52

0

如果您使用此代碼:

System.out.println(price*100); // Prints 434! 

你注意到它的輸出是

434.99999999999994

WH ich圓角是434

+0

但是爲什麼它首先放置了434.99999999999994?我用過的數字不應該給出答案。 – mino 2011-12-28 16:59:30

+0

@ m92 java不是數學家,正如其他人所說的,java在浮點精度方面有一些問題 – 2011-12-28 17:13:08

+1

@AdelBoutros它不是java問題,它是因爲double類型的二進制表示。 – 4ndrew 2011-12-28 17:20:25

2

IMO,使用BigDecimal的建議是矯枉過正。對於美分,請使用很長時間。即使是美國國債,也可以用美分來承保。

如果您使用浮點數(或雙精度),轉換爲整數時,請根據需要使用Math.round(),Math.floor()或Math.ceil()。

0

雙值4.35實際上表示爲4.349999999999999。 100 * 4.349999999999999 = 434.9999999999999。 並將其轉換爲int值將給你434.

+0

4.3499999999999996447286321199499070644378662109375,確切地說。 – dan04 2011-12-28 23:47:24