【java解惑】int轉化爲float精度問題


    如下代碼:

public class Example034 {

	public static void main(String[] args) {
		int count = 0;
		int start = 2000000000;
		for (float f = start; f < start + 64; f++) {
			count++;
		}
		System.out.println(count);
		count = 0;
		System.out.println("將循環控制條件的值加1後……");
		for (float f = start; f < start + 65; f++) {
			count++;
		}
		System.out.println(count);
	}
}


    輸出結果:

0
將循環控制條件的值加1後……


    結果分析:

    分析第一次循環,該循環只有在循環控制變量f比(float)(start+64)小的時候才執行。(start+64)初始類型是int,被自動執行從int到float的提升,這種提升是以損失精度爲代價的。由於f的初值太大,以至於在對其加上 64,然後將結果轉型爲 float 時,所產生的數值等於直接將 f 轉換成 float 的數值。所以第一次循環並未執行,打印了結果0。但是,第一次循環執行完成打印後,爲什麼第二次的循環卻成爲了無限循環,沒有任何輸出結果呢?

    首先我們先了解一下,如何知道兩個很大的float是否相等呢?比如2000000000和2000000064。關鍵是要觀察到 2, 000, 000, 000 有 10 個因子都是 2:它是一個 2 乘以 9 個 10,而每個 10 都是 5× 2。(2*(5*2)^9 == 2^10*5^9,2的10次方乘以5的9次方),這意味着 2, 000, 000, 000 的二進制表示是以10 個 0 結尾的。 64 的二進制表示只需要 7 位,所以將 64 加到 2, 000, 000, 000上不會對右邊7 位之外的其他位產生影響。 特別是, 從右邊數過來的第 8 位仍舊是 0。 提升這個 31 位的 int 到具有 24 位精度的 float 會在第 8 位四捨五入, 從而直接丟棄最右邊的 7 位。而最右邊的 7 位是2, 000, 000, 000 與 2, 000, 000, 064 的不同之處,因此它們的 float 表示是相同的。(藍字部分內容表示不確定正確性

    如果按照上述講解,那麼上述代碼的第二個循環應該同樣不可以執行的。但是,事實上,第二個循環執行了,但是是死循環。這是爲什麼呢?

    

    總之,不要使用浮點數作爲循環索引 ,因爲它會導致無法預測的行爲。如果你在循環體內 需要一個浮點數,那麼請使用 int 或 long 循環索引 ,並將其轉換爲 float 或 double。在將一個 int 或 long 轉換成一個 float 或 double時,你可能會丟失精度,但是至少它不會影響到循環本身。當你使用浮點數時,要使用 double 而不是 float,除非你肯定 float 提供了足夠的精度,並且存在強制性的性能需求迫使你使用 float。


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