C語言標(biāo)準(zhǔn)C89里規(guī)定了3種浮點(diǎn)數(shù),float型、double型和long double型,常見的浮點(diǎn)型長度為float型占4個(gè)字節(jié),double型占8個(gè)字節(jié),long double型長度要大于等于double型,下面將以float型為例進(jìn)行介紹,double型和long double型只是比float型位數(shù)長,原理是一樣的 。 float型可以表示的十進(jìn)制范圍是-3.402823466e38~3.402823466e38,而作為同為4個(gè)字節(jié)的定點(diǎn)數(shù)卻只能表示-2147483648~2147483647的范圍,使用同樣的內(nèi)存空間,浮點(diǎn)數(shù)卻能比定點(diǎn)數(shù)表示大得多的范圍,這是不是太神奇了?既然浮點(diǎn)數(shù)能表示這么大的范圍,那么我們?yōu)楹尾皇褂酶↑c(diǎn)數(shù)來代替定點(diǎn)數(shù)呢?先不說浮點(diǎn)數(shù)實(shí)現(xiàn)起來比較復(fù)雜,有些處理器還專門配置了硬件浮點(diǎn)運(yùn)算單元用于浮點(diǎn)運(yùn)算,主要原因是浮點(diǎn)數(shù)根本就無法取代定點(diǎn)數(shù),因?yàn)榫葐栴}。魚和熊掌不可兼得,浮點(diǎn)數(shù)表示了非常大的范圍,但它失去了精度。 ANSI/IEEE Std 754-1985標(biāo)準(zhǔn)
浮點(diǎn)表示的一般形式為(科學(xué)技術(shù)法規(guī)則):R=(S) * (1 + F) * 2e (R:實(shí)數(shù) S:正負(fù)符號(hào) F:小數(shù)部分 e:指數(shù),不同于指數(shù)偏差)。
例如,3.75的二進(jìn)制碼為11.11,將該二進(jìn)制碼按科學(xué)計(jì)數(shù)法表達(dá)為1.111,則向左移動(dòng)了1位,即e=1,E=e+127=128,F(xiàn)記錄的便是小數(shù)部分,實(shí)際為111000...000。 下面介紹一下小數(shù)部分轉(zhuǎn)換為二進(jìn)制碼的方式。類似于整數(shù)的形式(如7 = 22 + 21 + 20),小數(shù)部分的轉(zhuǎn)換形式為2-1、2-2、2-3、2-4......,例如0.5 = 2-1,即二進(jìn)制碼為0.1,0.05 = 2-5 + 2-6 + 2-9 + 2-10 + 2-13 + 2-14 +...... (可無限循環(huán)),即二進(jìn)制碼為0.00001100110011......。如果都以16位計(jì),那么7的二進(jìn)制碼為0000000000000111,0.5的二進(jìn)制碼為0.1000000000000000,0.05的二進(jìn)制碼為0.0000110011001100。這是如何換算出來的呢?且看下面的算法便知: 換算0.5,乘法結(jié)果初始為0.5,所有乘數(shù)為2,每次用乘法結(jié)果 * 乘數(shù),得到新的乘法結(jié)果,結(jié)果中的整數(shù)部分被提取出來,剩余的小數(shù)部分繼續(xù)參加下一次乘法運(yùn)算,直到剩余小數(shù)部分為0,或者無終點(diǎn)(無限循環(huán))。根據(jù)表格中的整數(shù)部分可知,二進(jìn)制為0.1。
換算0.05,乘法結(jié)果初始為0.05,所有乘數(shù)為2,每次用乘法結(jié)果 * 乘數(shù),得到新的乘法結(jié)果,結(jié)果中的整數(shù)部分被提取出來,剩余的小數(shù)部分繼續(xù)參加下一次乘法運(yùn)算,直到剩余小數(shù)部分為0,或者無終點(diǎn)(無限循環(huán))。根據(jù)表格中的整數(shù)部分可知,二進(jìn)制為0.00001100110011......。
例1:float型浮點(diǎn)數(shù)125.5轉(zhuǎn)化成32位二進(jìn)制浮點(diǎn)數(shù)。 125.5的整數(shù)和小數(shù)部分的二進(jìn)制碼分別為1111101和0.1,于是125.5的二進(jìn)制碼為1111101.1,按科學(xué)技術(shù)法寫為1.1111011*26,即向左移6位,則e=6,E=e+127=133,133的二進(jìn)制碼為10000101。而1.1111011把整數(shù)部分的1去掉后,剩下小數(shù)部分為1111011,之后補(bǔ)0至23位,構(gòu)成F。所以125.5的32位二進(jìn)制浮點(diǎn)數(shù)為: 例2:float型浮點(diǎn)數(shù)0.5轉(zhuǎn)化成32位二進(jìn)制浮點(diǎn)數(shù)。 類似的,0.5的二進(jìn)制碼為0.1,按科學(xué)技術(shù)法寫為1.0*2-1,即向右移1位,則e=-1,則E=e+127=126,126的二進(jìn)制碼為01111110。而1.0把整數(shù)部分的1去掉后,剩下小數(shù)部分為0,之后補(bǔ)0至23位,構(gòu)成F。所以0.5的32位二進(jìn)制浮點(diǎn)數(shù)為: 幾個(gè)特殊的情形
浮點(diǎn)數(shù)的精度 從前文中可以看到,1.xxx這類浮點(diǎn)數(shù)中,F(xiàn)部分最小的是2-23,對應(yīng)的十進(jìn)制數(shù)為1.00000011920928955078125,可以精確表示到小數(shù)點(diǎn)后23位,但是一些C語言書上卻說float型的有效位只有6~7位,這是為什么呢?原因在于二進(jìn)制小數(shù)與十進(jìn)制小數(shù)沒有完全一一對應(yīng)的關(guān)系,二進(jìn)制小數(shù)相比十進(jìn)制小數(shù)來說,是離散而不是連續(xù)的,我們來看看下面這些數(shù)字: 二進(jìn)制小數(shù) 十進(jìn)制小數(shù) 這里只需要關(guān)注F,上面列出了1.xxx這類浮點(diǎn)數(shù)中的6個(gè)最小的二進(jìn)制小數(shù),及其對應(yīng)的十進(jìn)制數(shù)??梢钥吹绞褂枚M(jìn)制所能表示的最小小數(shù)是1.00000011920928955078125,其次是1.0000002384185791015625,這兩個(gè)數(shù)之間是有間隔的,如果想用二進(jìn)制小數(shù)來表示8位有效數(shù)(只算小數(shù)部分,小數(shù)點(diǎn)前面的1是隱藏的默認(rèn)值)1.00000002、1.00000003、1.00000004......這些數(shù)是無法辦到的,而7位有效數(shù)1.0000001可以用2-23來表示,1.0000002可以用2-22來表示,1.0000003可以用2-23+2-22來表示。從這個(gè)角度來看,float型所能精確表示的位數(shù)只有7位,7位之后的數(shù)雖然也是精確表示的,但卻無法表示任意一個(gè)想表示的數(shù)值。 但還是有一些例外的,比如說7位有效數(shù)1.0000006這個(gè)數(shù)就無法用F表示,這也表明二進(jìn)制小數(shù)對于十進(jìn)制小數(shù)來說相當(dāng)于是離散的,剛好湊不出1.0000006這個(gè)數(shù),從這點(diǎn)來看float型所能精確表示的位數(shù)只有6位。因此float型的有效位數(shù)是6~7位,但這個(gè)說法應(yīng)該不是非常準(zhǔn)確,準(zhǔn)確來說應(yīng)該是6位,C語言的頭文件中規(guī)定也是6位。對于一個(gè)很大的數(shù),例如1234567890,它是由于指數(shù)E系數(shù)而被放大了的,但它的有效位仍然是F所能表示的6~7位有效數(shù)字。1234567890用float表示后為1234567936,只有高7位是有效位,后3位是無效的。int型可以準(zhǔn)確的表示1234567890,而float浮點(diǎn)數(shù)則只能近似的表示1234567890,精度問題決定了float型無法取代int型。
|
|