這個題目涉及float在計算機中的存儲問題, IEEE 754的標(biāo)準(zhǔn)就是描述的這個問題。如果這個題目放在筆試的時候應(yīng)該比面試的時候容易多了。
這個題目的幾個答案為1,1065353216(0x3f800000H),false,0,0,true。如果你已完美的答出這六個答案,就可以忽略后面的內(nèi)容。
無論是單精度還是雙精度在存儲中都分為三個部分:
1. 符號位(Sign) : 0代表正,1代表為負(fù)
2. 指數(shù)位(Exponent):用于存儲科學(xué)計數(shù)法中的指數(shù)數(shù)據(jù),并且采用移位存儲
3. 尾數(shù)部分(Mantissa):尾數(shù)部分
其中float的存儲方式如下圖所示:
指數(shù)部分(E) 占用8-bit的二進(jìn)制數(shù),可表示數(shù)值范圍為0-255?!〉侵笖?shù)應(yīng)可正可負(fù),所以IEEE規(guī)定,此處算出的次方須減去127才是真正的指數(shù)。所以float的指數(shù)可從 -126到128.
尾數(shù)部分(M)實際是占用24-bit的一個值,由于其最高位始終為 1 ,所以最高位省去不存儲,在存儲中只有23-bit。
符號位:s 通過(-1)的s次冪來表示正負(fù)號。
而雙精度的存儲方式為:
上圖中,|E|表示E的二進(jìn)制序列表示的整數(shù)值,例如E為"10000100",則|E|=132,e=132-127=5 。 k則表示E的位數(shù),對單精度來說,k=8,則bias=127,對雙精度來說,k=11,則bias=1023。
此時m的計算公式如下圖所示:
標(biāo)準(zhǔn)規(guī)定此時小數(shù)點左側(cè)的隱含位為1,那么m=|1.M|。如M="101",則|1.M|=|1.101|=1.625,即 m=1.625
2、非規(guī)格化:當(dāng)E的二進(jìn)制位全部為0時,N為非規(guī)格化形式。此時e,m的計算都非常簡單。
注意,此時小數(shù)點左側(cè)的隱含位為0。 為什么e會等于(1-bias)而不是(-bias),這主要是為規(guī)格化數(shù)值、非規(guī)格化數(shù)值之間的平滑過渡設(shè)計的。后文我們還會繼續(xù)討論。有了非規(guī)格化形式,我們就可以表示0了。把符號位S值1,其余所有位均置0后,我們得到了 -0.0; 同理,把所有位均置0,則得到 +0.0。非規(guī)格化數(shù)還有其他用途,比如表示非常接近0的小數(shù),而且這些小數(shù)均勻地接近0,稱為“逐漸下溢(gradually underflow)”屬性。
3、特殊數(shù)值:當(dāng)E的二進(jìn)制位全為1時為特殊數(shù)值。此時,若M的二進(jìn)制位全為0,則n表示無窮大,若S為1則為負(fù)無窮大,若S為0則為正無窮大; 若M的二進(jìn)制位不全為0時,表示NaN(Not a Number),表示這不是一個合法實數(shù)或無窮,或者該數(shù)未經(jīng)初始化。
對于1.0f這個數(shù)字,我們應(yīng)該如何表示?按照上面的規(guī)則可以得到,符號位為0,指數(shù)位為127(0x7F),尾數(shù)部分M應(yīng)該為全0。因此它在計算機中的存儲就是0x3F800000H。
cout << (int)a << endl;
把a從浮點數(shù)轉(zhuǎn)換為整數(shù),由于1.0f能夠使用32bits完整的表示,沒有舍入誤差,因此會輸出整數(shù) 1
cout << (int&)a << endl;
把a里面的內(nèi)容轉(zhuǎn)換為整數(shù)地址,因此編譯器會直接浮點數(shù)的32位表示直接輸出,,即0x3f800000h的10進(jìn)制表示。
對于0.0f這個特殊的表示上面已經(jīng)提到了,它在內(nèi)存中的存儲就是全0,因此直接把浮點數(shù)轉(zhuǎn)換為整數(shù)還是直接把浮點數(shù)的表示轉(zhuǎn)化為整數(shù)地址結(jié)果都是0。
正如上面提到的一樣,浮點數(shù)-0的表示和+0的表示是不同的,-0在內(nèi)存中的表示為0x80000000H。
最后再轉(zhuǎn)載一點關(guān)于long double的知識,我也沒有自己深入。
⑴ 擴展雙精度格式(SPARC 結(jié)構(gòu)計算機)
該4倍精度浮點環(huán)境符合IEEE關(guān)于擴展雙精度格式的定義。該浮點環(huán)境的4倍精度浮點格式共128位,占4個連續(xù)32位字,包含3個構(gòu)成字段:112位的小數(shù)f,15位的偏置指數(shù)e,和1位的符號s。將這4個連續(xù)的32位字整體作為一個128位的字,進(jìn)行重新編號。其中0:110位包含小數(shù)f;112:126位包含偏置指數(shù)e;第127位包含符號位s。如圖3所示。
在SPARC結(jié)構(gòu)計算機中,地址最高的32位字存放小數(shù)的32位最低有效位,即f[31:0];但是在PowerPC結(jié)構(gòu)計算機中,卻是地址最低的32位字存放這些位。
緊鄰的兩個32位字(在SPARC機中向下計算,在PowerPC機中向上計算)分別存放f[63:32]和f[95:64]。
最后一個字的第0到15位存放小數(shù)的最高16位,即f[111:96]。其中第0位存放該16位的最低有效位,第15位存放整個小數(shù)f的最高有效位。第16到30位存放15位的偏置指數(shù)e,其中第16位存放偏置指數(shù)的最低有效位,第30位存放它的最高有效位。最高位,第31位存放符號s。
⑵ 擴展雙精度格式(Intel x86結(jié)構(gòu)計算機)
該浮點環(huán)境雙精度擴展格式符合IEEE雙精度擴展格式的定義。該浮點環(huán)境的擴展雙精度格式共80位,占3個連續(xù)32位字,包含四個構(gòu)成字段:63位的小數(shù)f,1位顯式前導(dǎo)有效位(explicit leading significand bit)j,15位偏置指數(shù)e,和1位符號位s。將這3個連續(xù)的32位字整體作為一個96位的字,進(jìn)行重新編號。其中0:63包含63位的小數(shù)f,第63位包含前導(dǎo)有效位j,64:78位包含15位的偏置指數(shù)e,最高位第79位包含符號位s。
在Intel結(jié)構(gòu)系計算機中,這些字段依次存放在十個連續(xù)的字節(jié)中。但是,由于 UNIX System V Application Binary Interface Intel 386 Processor Supplement (Intel ABI) 要求雙精度擴展參數(shù),從而占用堆棧中3個相連地址的32位字,其中最高一個字的高16位未被使用。
地址最低的32位字存放小數(shù)f的低32位,即f[31:0]。其中第0位存放整個小數(shù)f的最低有效位LSB 第31位存放小數(shù)低32位的最高有效位MSB。
先說說32 位的 float型.
一個浮點數(shù) X, 在計算機中表示為:
X = a * 2e
這里 e 代表指數(shù), a 代表尾數(shù), 在 計算機內(nèi)部, 他們都是用二進(jìn)制表示的. 其中 a 用二進(jìn)制的科學(xué)表示法表示, 由于科學(xué)表示法第一位總是1 (0除外) , 所以第一位略去不計. e 表示的時候, 因為要表示出負(fù)數(shù), 所以 要加上127 , 實際運算的時候要減去 127.
IEEE 規(guī)定, 32 位 float型被拆開成以下格式, 左邊為高位 :
0 0000 0000 0000000 00000000 00000000
最高位,第32位 第 31-23位,共8位 第23-1位
符號位 指數(shù)位 尾數(shù)位
0為正,1為負(fù) -127~+127 0~0x 7f ff ff
float 的范圍是 -3.40282 * e38 ~ + 3.40282 * e38
一般在人看來是 十進(jìn)制的數(shù), 要轉(zhuǎn)換成二進(jìn)制. 十進(jìn)制轉(zhuǎn)二進(jìn)制, 大于1 的部分就是除以2 取余, 小于1 的部分乘2 取整(上計算機原理課,講了那么多東西就記得這句話了)
比如 8.5 轉(zhuǎn)換成二進(jìn)制就是 1000.1 , 處理成這一步, 還要用科學(xué)表示法表示, 就成了 1.0001 * 23 , 注意: 由于1.0001 第一個1 要去掉, 所以成了 0001 , 3 需要加上 127 就成了 130 (移碼運算,原碼加上2^n-1), 二進(jìn)制就是 10000011 套用上面話就表示為:
0 10000011 0001000 00000000 00000000
16 進(jìn)制 就是: 0x 41 98 00 00 , 一般來說 , intel 系列的 CPU 都使用的是 小尾存放, 就是 高字節(jié)放在后面, 剛好要掉過來就是: 0x 00 00 98 41 , 這樣就完成了一次浮點數(shù)的表示.
注意: 浮點數(shù) 0.0 在計算機中表示為 0x 00 00 00 00 .
那么浮點數(shù)的精度是怎么回事情呢? 當(dāng)我們使用二進(jìn)制表示 大于1 的部分的時候, 沒有問題, 除以2,一直下去, 最后一位肯定不是1 就是 0; 那么小數(shù)部分呢? 舉個例子, 比如 0.8
表示 0.8
* 2
1.6 - 1 = 0.6
* 2
1.2 -1 = 0.2 - 0
.* 2
0.4 - 0
*2
0.8 - 0
這樣就循環(huán)了 就是說 0.8 的二進(jìn)制 就是 0.11000 11000 ...... 一直循環(huán)下去, 而我們計算機如果表示0.8只能取0后面的前25位(第一個1 略去, ^_^), 這就說明 如果是 0.80000000000000000000000001 , 它表示出來的值其實是和 0.8 一樣, 所以我們比較float型的數(shù)字 用 a == b 其實是沒有根據(jù)的, 一般都是 用 abs(a - b) < 0.000001 (0.000001應(yīng)該是hex吧?此處涉及到數(shù)學(xué)的實數(shù)常識,公式|a-b|<c 轉(zhuǎn)換成 -c<a-b<c)之類就默認(rèn)是相等. 所以這就出現(xiàn)了經(jīng)典的 \精度問題.
那么 double型呢? 咱們可以照 float 型的葫蘆 來畫了.
double 型 只是說 取 64 位, 比float型的位 多一倍, 但是同樣 逃不出精度的五指山. :)
IEEE 規(guī)定 double 型 ,
第64位 63-54 53-1
符號位 指數(shù)位 ( -1024 - 1024) 尾數(shù)位
所以 double型的范圍是 -1.79769 * e308 ~ +1.79769 * e308
多用了幾位, 表示范圍大了很多, 其實本質(zhì)跟float型一樣.
看來計算機是用來計算的, 一點都不假, 所謂機器智能, 也是人加上去的, 這就更不用懷疑了.
本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/zjumath/archive/2009/05/12/4174248.aspx