下面的謎題以及隨后的五個(gè)謎題對(duì)你來(lái)說(shuō)是扭轉(zhuǎn)了局面,它們不是向你展示某些代碼,然后詢問(wèn)你這些代碼將做些什么,它們要讓你去寫(xiě)代碼,但是數(shù)量會(huì)很少。這些謎題被稱為“循環(huán)者(looper)”。你眼前會(huì)展示出一個(gè)循環(huán),它看起來(lái)應(yīng)該很快就終止的,而你的任務(wù)就是寫(xiě)一個(gè)變量聲明,在將它作用于該循環(huán)之上時(shí),使得該循環(huán)無(wú)限循環(huán)下去。例如,考慮下面的for循環(huán):
for (int i = start; i <= start + 1; i++) {}
看起來(lái)它好像應(yīng)該只迭代兩次,但是通過(guò)利用在謎題26中所展示的溢出行為,可以使它無(wú)限循環(huán)下去。下面的的聲明就采用了這項(xiàng)技巧:
int start = Integer.MAX_VALUE - 1;
現(xiàn)在該輪到你了。什么樣的聲明能夠讓下面的循環(huán)變成一個(gè)無(wú)限循環(huán)?
While (i == i + 1) {}
仔細(xì)查看這個(gè)while循環(huán),它真的好像應(yīng)該立即終止。一個(gè)數(shù)字永遠(yuǎn)不會(huì)等于它自己加1,對(duì)嗎?嗯,如果這個(gè)數(shù)字是無(wú)窮大的,又會(huì)怎樣呢?Java強(qiáng)制要求使用IEEE 754浮點(diǎn)數(shù)算術(shù)運(yùn)算[IEEE 754],它可以讓你用一個(gè)double或float來(lái)表示無(wú)窮大。正如我們?cè)趯W(xué)校里面學(xué)到的,無(wú)窮大加1還是無(wú)窮大。如果i在循環(huán)開(kāi)始之前被初始化為無(wú)窮大,那么終止條件測(cè)試(i == i + 1)就會(huì)被計(jì)算為true,從而使循環(huán)永遠(yuǎn)都不會(huì)終止。
你可以用任何被計(jì)算為無(wú)窮大的浮點(diǎn)算術(shù)表達(dá)式來(lái)初始化i,例如:
double i = 1.0 / 0.0;
不過(guò),你是能夠利用標(biāo)準(zhǔn)類(lèi)庫(kù)為你提供的常量:
double i = Double.POSITIVE_INFINITY;
事實(shí)上,你不必將i初始化為無(wú)窮大以確保循環(huán)永遠(yuǎn)執(zhí)行。任何足夠大的浮點(diǎn)數(shù)都可以實(shí)現(xiàn)這一目的,例如:
double i = 1.0e40;
這樣做之所以可以起作用,是因?yàn)橐粋€(gè)浮點(diǎn)數(shù)值越大,它和其后繼數(shù)值之間的間隔就越大。浮點(diǎn)數(shù)的這種分布是用固定數(shù)量的有效位來(lái)表示它們的必然結(jié)果。對(duì)一個(gè)足夠大的浮點(diǎn)數(shù)加1不會(huì)改變它的值,因?yàn)?是不足以“填補(bǔ)它與其后繼者之間的空隙”。
浮點(diǎn)數(shù)操作返回的是最接近其精確的數(shù)學(xué)結(jié)果的浮點(diǎn)數(shù)值。一旦毗鄰的浮點(diǎn)數(shù)值之間的距離大于2,那么對(duì)其中的一個(gè)浮點(diǎn)數(shù)值加1將不會(huì)產(chǎn)生任何效果,因?yàn)槠浣Y(jié)果沒(méi)有達(dá)到兩個(gè)數(shù)值之間的一半。對(duì)于float類(lèi)型,加1不會(huì)產(chǎn)生任何效果的最小級(jí)數(shù)是225,即33,554,432;而對(duì)于double類(lèi)型,最小級(jí)數(shù)是254,大約是1.8 × 1016。
毗鄰的浮點(diǎn)數(shù)值之間的距離被稱為一個(gè)ulp,它是“最小單位(unit in the last place)”的首字母縮寫(xiě)詞。在5.0版中,引入了Math.ulp方法來(lái)計(jì)算float或double數(shù)值的ulp。
總之,用一個(gè)double或一個(gè)float數(shù)值來(lái)表示無(wú)窮大是可以的。大多數(shù)人在第一次聽(tīng)到這句話時(shí),多少都會(huì)有一點(diǎn)吃驚,可能是因?yàn)槲覀儫o(wú)法用任何整數(shù)類(lèi)型來(lái)表示無(wú)窮大的原因。第二點(diǎn),將一個(gè)很小的浮點(diǎn)數(shù)加到一個(gè)很大的浮點(diǎn)數(shù)上時(shí),將不會(huì)改變大的浮點(diǎn)數(shù)的值。這過(guò)于違背直覺(jué)了,因?yàn)閷?duì)實(shí)際的數(shù)字來(lái)說(shuō)這是不成立的。我們應(yīng)該記住二進(jìn)制浮點(diǎn)算術(shù)只是對(duì)實(shí)際算術(shù)的一種近似。
for (int i = start; i <= start + 1; i++) {}
看起來(lái)它好像應(yīng)該只迭代兩次,但是通過(guò)利用在謎題26中所展示的溢出行為,可以使它無(wú)限循環(huán)下去。下面的的聲明就采用了這項(xiàng)技巧:
int start = Integer.MAX_VALUE - 1;
現(xiàn)在該輪到你了。什么樣的聲明能夠讓下面的循環(huán)變成一個(gè)無(wú)限循環(huán)?
While (i == i + 1) {}
仔細(xì)查看這個(gè)while循環(huán),它真的好像應(yīng)該立即終止。一個(gè)數(shù)字永遠(yuǎn)不會(huì)等于它自己加1,對(duì)嗎?嗯,如果這個(gè)數(shù)字是無(wú)窮大的,又會(huì)怎樣呢?Java強(qiáng)制要求使用IEEE 754浮點(diǎn)數(shù)算術(shù)運(yùn)算[IEEE 754],它可以讓你用一個(gè)double或float來(lái)表示無(wú)窮大。正如我們?cè)趯W(xué)校里面學(xué)到的,無(wú)窮大加1還是無(wú)窮大。如果i在循環(huán)開(kāi)始之前被初始化為無(wú)窮大,那么終止條件測(cè)試(i == i + 1)就會(huì)被計(jì)算為true,從而使循環(huán)永遠(yuǎn)都不會(huì)終止。
你可以用任何被計(jì)算為無(wú)窮大的浮點(diǎn)算術(shù)表達(dá)式來(lái)初始化i,例如:
double i = 1.0 / 0.0;
不過(guò),你是能夠利用標(biāo)準(zhǔn)類(lèi)庫(kù)為你提供的常量:
double i = Double.POSITIVE_INFINITY;
事實(shí)上,你不必將i初始化為無(wú)窮大以確保循環(huán)永遠(yuǎn)執(zhí)行。任何足夠大的浮點(diǎn)數(shù)都可以實(shí)現(xiàn)這一目的,例如:
double i = 1.0e40;
這樣做之所以可以起作用,是因?yàn)橐粋€(gè)浮點(diǎn)數(shù)值越大,它和其后繼數(shù)值之間的間隔就越大。浮點(diǎn)數(shù)的這種分布是用固定數(shù)量的有效位來(lái)表示它們的必然結(jié)果。對(duì)一個(gè)足夠大的浮點(diǎn)數(shù)加1不會(huì)改變它的值,因?yàn)?是不足以“填補(bǔ)它與其后繼者之間的空隙”。
浮點(diǎn)數(shù)操作返回的是最接近其精確的數(shù)學(xué)結(jié)果的浮點(diǎn)數(shù)值。一旦毗鄰的浮點(diǎn)數(shù)值之間的距離大于2,那么對(duì)其中的一個(gè)浮點(diǎn)數(shù)值加1將不會(huì)產(chǎn)生任何效果,因?yàn)槠浣Y(jié)果沒(méi)有達(dá)到兩個(gè)數(shù)值之間的一半。對(duì)于float類(lèi)型,加1不會(huì)產(chǎn)生任何效果的最小級(jí)數(shù)是225,即33,554,432;而對(duì)于double類(lèi)型,最小級(jí)數(shù)是254,大約是1.8 × 1016。
毗鄰的浮點(diǎn)數(shù)值之間的距離被稱為一個(gè)ulp,它是“最小單位(unit in the last place)”的首字母縮寫(xiě)詞。在5.0版中,引入了Math.ulp方法來(lái)計(jì)算float或double數(shù)值的ulp。
總之,用一個(gè)double或一個(gè)float數(shù)值來(lái)表示無(wú)窮大是可以的。大多數(shù)人在第一次聽(tīng)到這句話時(shí),多少都會(huì)有一點(diǎn)吃驚,可能是因?yàn)槲覀儫o(wú)法用任何整數(shù)類(lèi)型來(lái)表示無(wú)窮大的原因。第二點(diǎn),將一個(gè)很小的浮點(diǎn)數(shù)加到一個(gè)很大的浮點(diǎn)數(shù)上時(shí),將不會(huì)改變大的浮點(diǎn)數(shù)的值。這過(guò)于違背直覺(jué)了,因?yàn)閷?duì)實(shí)際的數(shù)字來(lái)說(shuō)這是不成立的。我們應(yīng)該記住二進(jìn)制浮點(diǎn)算術(shù)只是對(duì)實(shí)際算術(shù)的一種近似。