請?zhí)峁┮粋€對i的聲明,將下面的循環(huán)轉(zhuǎn)變?yōu)橐粋€無限循環(huán):
while (i != i) {
}
這個循環(huán)可能比前一個還要使人感到困惑。不管在它前面作何種聲明,它看起來確實應(yīng)該立即終止。一個數(shù)字總是等于它自己,對嗎?
對,但是IEEE 754浮點算術(shù)保留了一個特殊的值用來表示一個不是數(shù)字的數(shù)量[IEEE 754]。這個值就是NaN(“不是一個數(shù)字(Not a Number)”的縮寫),對于所有沒有良好的數(shù)字定義的浮點計算,例如0.0/0.0,其值都是它。規(guī)范中描述道,NaN不等于任何浮點數(shù)值,包括它自身在內(nèi)[JLS 15.21.1]。因此,如果i在循環(huán)開始之前被初始化為NaN,那么終止條件測試(i != i)的計算結(jié)果就是true,循環(huán)就永遠(yuǎn)不會終止。很奇怪但卻是事實。
你可以用任何計算結(jié)果為NaN的浮點算術(shù)表達(dá)式來初始化i,例如:
double i = 0.0 / 0.0;
同樣,為了表達(dá)清晰,你可以使用標(biāo)準(zhǔn)類庫提供的常量:
double i = Double.NaN;
NaN還有其他的驚人之處。任何浮點操作,只要它的一個或多個操作數(shù)為NaN,那么其結(jié)果為NaN。這條規(guī)則是非常合理的,但是它卻具有奇怪的結(jié)果。例如,下面的程序?qū)⒋蛴alse:
class Test {
public static void main(String[] args) {
double i = 0.0 / 0.0;
System.out.println(i - i == 0);
}
}
這條計算NaN的規(guī)則所基于的原理是:一旦一個計算產(chǎn)生了NaN,它就被損壞了,沒有任何更進(jìn)一步的計算可以修復(fù)這樣的損壞。NaN值意圖使受損的計算繼續(xù)執(zhí)行下去,直到方便處理這種情況的地方為止。
總之,float和double類型都有一個特殊的NaN值,用來表示不是數(shù)字的數(shù)量。對于涉及NaN值的計算,其規(guī)則很簡單也很明智,但是這些規(guī)則的結(jié)果可能是違背直覺的。
while (i != i) {
}
這個循環(huán)可能比前一個還要使人感到困惑。不管在它前面作何種聲明,它看起來確實應(yīng)該立即終止。一個數(shù)字總是等于它自己,對嗎?
對,但是IEEE 754浮點算術(shù)保留了一個特殊的值用來表示一個不是數(shù)字的數(shù)量[IEEE 754]。這個值就是NaN(“不是一個數(shù)字(Not a Number)”的縮寫),對于所有沒有良好的數(shù)字定義的浮點計算,例如0.0/0.0,其值都是它。規(guī)范中描述道,NaN不等于任何浮點數(shù)值,包括它自身在內(nèi)[JLS 15.21.1]。因此,如果i在循環(huán)開始之前被初始化為NaN,那么終止條件測試(i != i)的計算結(jié)果就是true,循環(huán)就永遠(yuǎn)不會終止。很奇怪但卻是事實。
你可以用任何計算結(jié)果為NaN的浮點算術(shù)表達(dá)式來初始化i,例如:
double i = 0.0 / 0.0;
同樣,為了表達(dá)清晰,你可以使用標(biāo)準(zhǔn)類庫提供的常量:
double i = Double.NaN;
NaN還有其他的驚人之處。任何浮點操作,只要它的一個或多個操作數(shù)為NaN,那么其結(jié)果為NaN。這條規(guī)則是非常合理的,但是它卻具有奇怪的結(jié)果。例如,下面的程序?qū)⒋蛴alse:
class Test {
public static void main(String[] args) {
double i = 0.0 / 0.0;
System.out.println(i - i == 0);
}
}
這條計算NaN的規(guī)則所基于的原理是:一旦一個計算產(chǎn)生了NaN,它就被損壞了,沒有任何更進(jìn)一步的計算可以修復(fù)這樣的損壞。NaN值意圖使受損的計算繼續(xù)執(zhí)行下去,直到方便處理這種情況的地方為止。
總之,float和double類型都有一個特殊的NaN值,用來表示不是數(shù)字的數(shù)量。對于涉及NaN值的計算,其規(guī)則很簡單也很明智,但是這些規(guī)則的結(jié)果可能是違背直覺的。

