2012-02-17 58 views
1

可能重複:
java for-loop problem古怪的輸出採用浮點數作爲保護

爲什麼是下面的代碼的輸出:

for (float j2 = 0.0f; j2 < 10.0f; j2+=0.1f) { 
    System.out.println(j2); 
} 

此:

0.0 
0.1 
0.2 
0.3 
0.4 
0.5 
0.6 
0.70000005 
0.8000001 
0.9000001 
1.0000001 
1.1000001 
1.2000002 
1.3000002 
1.4000002 
1.5000002 
1.6000003 
1.7000003 
1.8000003 
1.9000003 
2.0000002 
2.1000001 
2.2 
2.3 
2.3999999 
2.4999998 
2.5999997 
2.6999996 
2.7999995 
2.8999994 
2.9999993 
3.0999992 
3.199999 
3.299999 
3.399999 
3.4999988 
3.5999987 
3.6999986 
3.7999985 
3.8999984 
3.9999983 
4.0999985 
4.1999984 
4.2999983 
4.399998 
4.499998 
4.599998 
4.699998 
4.799998 
4.8999977 
4.9999976 
5.0999975 
5.1999974 
5.2999973 
5.399997 
5.499997 
5.599997 
5.699997 
5.799997 
5.8999968 
5.9999967 
6.0999966 
6.1999965 
6.2999964 
6.3999963 
6.499996 
6.599996 
6.699996 
6.799996 
6.899996 
6.9999957 
7.0999956 
7.1999955 
7.2999954 
7.3999953 
7.499995 
7.599995 
7.699995 
7.799995 
7.899995 
7.9999948 
8.099995 
8.199995 
8.299995 
8.399996 
8.499996 
8.599997 
8.699997 
8.799997 
8.899998 
8.999998 
9.099998 
9.199999 
9.299999 
9.4 
9.5 
9.6 
9.700001 
9.800001 
9.900002 

還有一個問題:即使我將for循環的條件更改爲j2<=10.0f的輸出也是一樣的。爲什麼這樣?它不應該包含10.0的輸出嗎?

+2

你說的O/P是什麼意思?如果你的意思是「輸出」,請輸入單詞 – Nanne 2012-02-17 09:59:48

+0

是o/p =輸出。爲您更新。 ; p – 2012-02-17 10:01:24

+0

可能是一個精確的錯誤。 – 2012-02-17 10:02:03

回答

5

正如其他人已經提到它是關於浮點數的精度和每個操作步驟可能會增加錯誤的事實。

這就是爲什麼你從不使用浮動來代表金錢。查看BigDecimal的精確十進制處理。

10.0不包括的原因是總和已經浮動,不再是< = 10.0,因爲精度/舍入誤差已經漂移到+0.0以上。 9.900002 + 0.1可能會產生像10.000002這是> 10.0。

浮游物不是以精確的數字表示,而是作爲一個係數和一個指數,如(−1)^s × c × b^q,並且加入到浮游物中會結合兩個數字的不確定性。由於失去精度,這可能會轉化爲0.70000005而不是0.7。

退房http://en.wikipedia.org/wiki/IEEE_754-2008

1

Floating-Point Guide

爲什麼我的數字,像0.1 + 0.2加起來一個漂亮的圓0.3, 而是我得到一個奇怪的結果一樣0.30000000000000004?

由於內部計算機使用格式(二進制浮點數) ,因此無法準確表示數字,如0.1,0.2或0.3。

當代碼被編譯或解釋時,您的「0.1」已經被 舍入到該格式的最接近的數字,即使在計算髮生之前,這也會導致一個小的舍入誤差。

4

兩個doublefloat從計算和表示錯誤舍入誤差(對於其值不能完全代表)使用float比使用double這是一個很好的理由,以避免更多的錯誤。錯誤可能會大約10^8倍。

當您打印一個浮點數時,它將執行少量四捨五入來隱藏這個錯誤。該錯誤可以很容易地顯示出來。

因此,通過定義所需的準確度來自動舍入結果通常是一個好主意。

for (float j2 = 0.0f; j2 < 10.05f; j2+=0.1f) 
    System.out.printf("%.1f ", j2); 

0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 7.9 8.0 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 9.0 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 10.0

您可以看到使用的BigDecimal 0.1F的精確表示。有趣的是0.1f0.1是不一樣的價值。

System.out.println("0.1f = " + new BigDecimal(0.1f)); 
System.out.println("0.1 = " + new BigDecimal(0.1)); 
System.out.println("0.1f - 0.1 = " + (0.1f - 0.1) + " or " + new BigDecimal(0.1f - 0.1)); 

打印

0.1f = 0.100000001490116119384765625 
0.1 = 0.1000000000000000055511151231257827021181583404541015625 
0.1f - 0.1 = 1.4901161138336505E-9 or 1.4901161138336505018742172978818416595458984375E-9 

正如已經指出的那樣,你可以不使用浮動單獨的錢(或許多其他用途)點不懂事四捨五入。如果代碼的性能和可讀性不是問題,請改用BigDecimal。