謎題28: 迴圈者
現在該輪到你了。什麼樣的聲明能夠讓下面的迴圈變成一個無限迴圈?
while (i == i + 1)
{
}
解惑28: 迴圈者
仔細查看這個while迴圈,它真的好像應該立即終止。一個數字永遠不會等於它自己加1,對嗎?嗯,如果這個數字是無窮大的,又會怎樣呢?C#強制要求使用IEEE 754浮點算術運算,它可以讓你用一個double或float來表示無窮大。正如我們在學校裡學到的,無窮大加1還是無窮大。如果i在迴圈開始之前被初始化為無窮大,那麼終止條件測試(i == i + 1)就會被計算為true,從而使迴圈永遠不會終止。
可以用任何被計算為無窮大的浮點算術運算式來初始化i,例如:
double i = 1.0 / 0.0;
不過,最好是能夠利用標準類庫提供的常量:
double i = double.PositiveInfinity;
事實上,不必將i初始化為無窮大以確保迴圈永遠執行。任何足夠大的浮點數都可以實現這一目的,例如:
double i = 1.0e40;
這樣做之所以起作用,是因為一個浮點數值越大,它和其後繼數值之間的間隔就越大。浮點數的這種分布是固定數量的有效位來表示它們的必然結果。對一個足夠大的浮點數加1不會改變它的值,因為1不足以“填補它與其後繼者之間的空隙”。
浮點數操作返回的是最接近其精確數學結果的浮點數值。一旦毗鄰的浮點數值之間的距離大於2,那麼對其中的一個浮點數值加1不會產生任何效果,因為其結果沒有達到兩個數值之間的一半。對於float類型,加1不會產生任何效果的最小級數是225,即33,554,432;而對於double類型,最小級數是254,大約是1.8e16。
毗鄰的浮點數值之間的距離被稱為一個ulp,它是最小單位(unit in the last place)的首字母縮寫詞。
總之,
用一個double或float數值來表示無窮大是可以的。大多數人在第一次聽到這句話時,多少都會有一點吃驚,可能是因為無法用任何整數類型來表示無窮大的原因。第二點,
將一個很小的浮點數加到一個很大的浮點數上時,將不會改變大浮點數的值。這過於違背直覺了,因為對實際的數字來說這是不成立的。我們應該記住
二進位浮點算術只是對實際算術的一種近似。
C#解惑總目錄