2014-02-23 68 views
3

當我運行下面發佈的程序時,我得到了一些奇怪的結果。浮點變量不工作

該程序假設打印消息的倍數爲i = 5,000,000,但是,當我不等於500萬的倍數時,它有時會打印消息。

當我將numberOfTests從5000萬更改爲500萬時,程序運行良好。另外,如果我將它從float更改爲double,則該程序也可以正常工作。

我現在的代碼有什麼問題?浮動變量不工作?這是爲什麼發生?我今後如何防止這種情況發生?

public static void main(String[] args) 
{ 
    final int numberOfTests = 50 * 1000 * 1000; 
    final float IncrementsPercentageToPrintResults = .10f; 

    for(int i = 1; i <= numberOfTests; i++) 
    { 
     if(i % (IncrementsPercentageToPrintResults * numberOfTests) == 0) 
     { 
      System.out.println("Currently at " + (int) (((float) i/numberOfTests) * 100) + "%."); 
      System.out.println(" i = " + i);     
     } 
    } 

} 

Output: 
Currently at 10%. 
i = 5000000 
Currently at 20%. 
i = 10000000 
Currently at 30%. 
i = 15000000 
Currently at 40%. 
i = 19999999 
Currently at 40%. 
i = 20000000 
Currently at 40%. 
i = 20000001 
Currently at 50%. 
i = 24999999 
Currently at 50%. 
i = 25000000 
Currently at 50%. 
i = 25000001 
Currently at 60%. 
i = 29999999 
Currently at 60%. 
i = 30000000 
Currently at 60%. 
i = 30000001 
Currently at 70%. 
i = 34999998 
Currently at 70%. 
i = 34999999 
Currently at 70%. 
i = 35000000 
Currently at 70%. 
i = 35000001 
Currently at 70%. 
i = 35000002 
Currently at 80%. 
i = 39999998 
Currently at 80%. 
i = 39999999 
Currently at 80%. 
i = 40000000 
Currently at 80%. 
i = 40000001 
Currently at 80%. 
i = 40000002 
Currently at 90%. 
i = 44999998 
Currently at 90%. 
i = 44999999 
Currently at 90%. 
i = 45000000 
Currently at 90%. 
i = 45000001 
Currently at 90%. 
i = 45000002 
Currently at 100%. 
i = 49999998 
Currently at 100%. 
i = 49999999 
Currently at 100%. 
i = 50000000 
+1

我認爲[這個鏈接](http://www.youtube.com/watch?v=PZRI1IfStY0&list= UU9-y-6csu5WGm29I7JiwpnA&feature = share&index = 7)將揭示這個問題。 – Makoto

+0

這有助於很多!謝謝 – Programmer

+0

可能重複的[是浮點數學破碎?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) –

回答

6

這是因爲叫做numeric promotion。任何時候都有涉及兩種不同類型數字的表達式,「最窄」數字會被提升爲「最寬」數字。

你有一個表達這樣的位置:

if(i % (IncrementsPercentageToPrintResults * numberOfTests) == 0) 

這裏,IncrementPercentageToPrintResults是float所以它發生在表達每隔數提升爲浮動。

問題是,對於大數字,float實際上比int小。

所以實際上,對於一個float,在2^24(±16,777,216)之後,它不能再表示奇數。所以像19,999,999這樣的數字四捨五入到20,000,000。數字越大,浮點越不精確。

有很多解決方案,這裏最好的方法就是不用一個浮點數乘以一個int來完成除法。只是劃分numberOfTests 10:

if(i % (IncrementsPercentageToPrintResults/10) == 0) 

其他OK的解決方案是雙改用浮動的,因爲雙可以在一個int代表所有值完全相同。

另一個原因是,如果你真的想,所得到的浮動轉換爲int:

(int)(IncrementsPercentageToPrintResults * numberOfTests) 

然而,乘法表達式仍然四捨五入浮動,使得只有在這裏工作,因爲浮動可以代表價值500萬究竟。有時候這樣的演員是必要的,但這不是。只需使用除法或雙精度。

兩個強制性鏈接:

2

問題是與下面的行:

i % (IncrementsPercentageToPrintResults * numberOfTests) 

(IncrementsPercentageToPrintResults * numberOfTests)是浮動因爲IncrementsPercentageToPrintResults的類型,它不應該與模運算符可以使用的。快速解決方案如下:

i % (int)(IncrementsPercentageToPrintResults * numberOfTests) 

這會將結果強制轉換爲解決此問題的整數。