C語言中的浮點(diǎn)數(shù)存儲(chǔ)詳解
1、首先明確一個(gè)概念
C語言中整形是按照二進(jìn)制存儲(chǔ)在內(nèi)存中,浮點(diǎn)型是按科學(xué)計(jì)數(shù)法存儲(chǔ)在內(nèi)存中(本質(zhì)上存儲(chǔ)的還是二進(jìn)制數(shù)據(jù)0和1)。
如果沒看懂這句話,沒關(guān)系!看完以下正文,你就會(huì)豁然開朗!并且預(yù)先提出兩個(gè)問題:
1)為什么浮點(diǎn)型不能執(zhí)行位運(yùn)算?
2)浮點(diǎn)型數(shù)據(jù)轉(zhuǎn)換為整形數(shù)據(jù)時(shí),編譯器內(nèi)部做了什么樣的處理?
2、接下來,講解C語言中浮點(diǎn)型數(shù)存儲(chǔ)的規(guī)則
c語言中的浮點(diǎn)型有如下幾種 (float ,double ,longdouble),因?yàn)椴煌到y(tǒng)平臺(tái)下數(shù)據(jù)類型的長度會(huì)不一樣,這里我們統(tǒng)一在32位GCC編譯器下, float=4Byte,double=8個(gè)Byte
先定義
float num_1=10.5f; /* 這里有個(gè)小知識(shí)點(diǎn),很多編譯器中,如果10.5后面不加f(小寫),會(huì)默認(rèn)為存儲(chǔ)為double類型*/ double num_2 = 11.5
根據(jù)國際電器和電子工程協(xié)會(huì),標(biāo)準(zhǔn)IEEE754規(guī)定,浮點(diǎn)數(shù)可以按照以下規(guī)則存儲(chǔ)
(-1)^S*M*2^E
2.1、可以將上述公式分為兩部分來看
(-1)^S是確定數(shù)字是整數(shù)還是負(fù)數(shù)。M*2^E確定的數(shù)字絕對值的大小。
- 這里的M必須是二進(jìn)制數(shù)。有些資料把M叫做尾數(shù)
- S必須是整數(shù)1,或整數(shù)0。有些資料把S叫做數(shù)符
- E也必須是>=0的整數(shù)。有些資料把E叫做階碼
結(jié)合圖形來看:
C語言存儲(chǔ)浮點(diǎn)型數(shù)據(jù)float時(shí),會(huì)將內(nèi)存分為三個(gè)區(qū)域。結(jié)合實(shí)例我們來看
float num_1=10.5,先轉(zhuǎn)換為IEEE754格式,首先該數(shù)為正數(shù)故s=0;(-1)^0=0,符號位=0,表示正數(shù)。
- 第1步:在把10.5轉(zhuǎn)換為科學(xué)計(jì)數(shù)法 1.05*10^1,
- 第2步:再把10.5二進(jìn)制格式,其中M要為二進(jìn)制數(shù)據(jù),dec(10.5)=bin(1010.1)
- 第3步:二進(jìn)制寫成科學(xué)計(jì)數(shù)法10.5=1010.1*2^0 = 1.0101*2^3。
10.5為正數(shù)于是 31符號位S=0、E=3 =0000 0011 。有效數(shù)字M=1.0101。但是如果你按上述來寫,肯定是錯(cuò)誤的。浮點(diǎn)數(shù)存儲(chǔ)時(shí),還要遵守一定的轉(zhuǎn)換方式:轉(zhuǎn)換規(guī)則如下(也是很重要的一個(gè)知識(shí)點(diǎn))
(規(guī)則1)1<=M<2。IEEE 754規(guī)定 M只存儲(chǔ)小數(shù)部分,于是10.5只會(huì)存儲(chǔ)0101,系統(tǒng)會(huì)默認(rèn)最高位為1(。
(規(guī)則2)而E,存儲(chǔ)時(shí):
- float類型數(shù)據(jù),存儲(chǔ)值=E+127.
- double類型數(shù)據(jù),存儲(chǔ)值=E+1023.
首先得明確是一個(gè)無符號數(shù),10.5=1.0101*2^3,E=3,二進(jìn)制表示為 0000 0011。IEEE754規(guī)定了。對于32bit長度的float類型。E需要加上127,在此得到的數(shù),再存儲(chǔ)到內(nèi)存中去,我們把這個(gè)值叫做E的存儲(chǔ)值。3+127=129=1000 0010。double類型,應(yīng)該加上1023。至于為什么,后面細(xì)說。
M的0101,應(yīng)該左移到22-19bit位處
于是10.5的正確格式應(yīng)該是上圖所示的格式。
至于E為什么要+127(float)+1023(double),下面會(huì)介紹。
2.2、問:十進(jìn)制小數(shù)0.5該如何存儲(chǔ)?
轉(zhuǎn)換為二進(jìn)制科學(xué)計(jì)數(shù)法1*2^-1。如果我們E不做處理。
將會(huì)有如下問題,s=0,沒有問題,E=-1,E是無符號數(shù),不能顯示為-1。M存儲(chǔ)的是小數(shù)部分,全部存儲(chǔ)為0。
故:為了解決E無法表示負(fù)數(shù)的問題,才引入了E+127(Float),和E+1023(double)。為了描述方便,下面統(tǒng)一以float類型為例,當(dāng)E存儲(chǔ)值<127時(shí),認(rèn)定E為負(fù)數(shù),如E存儲(chǔ)值為125,則E的實(shí)際值為-2。當(dāng)E的存儲(chǔ)值>127時(shí),E的真實(shí)值為正數(shù),130=3。以此類推。。。。
故,本質(zhì)上E存儲(chǔ)時(shí)需要+127或+1023是為了解決浮點(diǎn)數(shù),(-1,1)注意是不包含邊界數(shù)的關(guān)系,的存儲(chǔ)問題。
E不全為0或不全為1
比如:
- 0.5(1/2)的二進(jìn)制形式為0.1,由于規(guī)定正數(shù)部分必須為1,即將小數(shù)點(diǎn)右移1位,則為 1.0*2^(-1),其E為-1+127=126,表示為:
- 01111110,而尾數(shù)1.0去掉整數(shù)部分為0,補(bǔ)齊0到23位00000000000000000000000,則其二進(jìn) 制表示形式為:
- 0 01111110 000000000000000000000001
另外還有兩種比較特殊的情況,E全為0和E全為1
這時(shí),浮點(diǎn)數(shù)就采用下面的規(guī)則表示,即指數(shù)E的計(jì)算值減去127(或1023),得到真實(shí)值,再將 有效數(shù)字M前加上第一位的1。
E全為0
- 這時(shí),浮點(diǎn)數(shù)的指數(shù)E等于1-127(或者1-1023)即為真實(shí)值, 有效數(shù)字M不再加上第一位的1,而是還原為0.xxxxxx的小數(shù)。這樣做是為了表示±0,以及接近于 0的很小的數(shù)字。
E全為1
- 這時(shí),如果有效數(shù)字M全為0,表示±無窮大(正負(fù)取決于符號位s);
2.3 浮點(diǎn)數(shù)存儲(chǔ)時(shí)的誤差
float Val_1=0.6f;
此時(shí)我們算一下,常量0.6f是如何存儲(chǔ)的。使用2進(jìn)制來表示的話,我們知道2^-1=0.5、2^-2=0.25、2^-3=0.125、2^-4=0.0625......
故我們使用0.1b=0.5,還需要表示出10進(jìn)制的小數(shù)0.1。從上面的例子也可以看出,實(shí)際上浮點(diǎn)數(shù)存儲(chǔ)時(shí),是無法準(zhǔn)確的表示出0.1的。所以只能采取一種無限逼近的方法,0.6的二進(jìn)制表示是0.1001100110011...(無限循環(huán)),如果需要有限位數(shù)的表示,可以根據(jù)需要選擇適當(dāng)?shù)奈粩?shù)進(jìn)行截取。例如,取4位小數(shù),則表示為0.1001。使用二進(jìn)制科學(xué)計(jì)數(shù)法為1.001*2^-1.
存儲(chǔ)時(shí):
S=0; E=-1+126=125; M=001
3、回答一開始提出的兩個(gè)問題
3.1、為什么浮點(diǎn)數(shù)不能執(zhí)行位運(yùn)算;
答:整形執(zhí)行位運(yùn)算,準(zhǔn)確的來說是無符號整形,才能執(zhí)行位運(yùn)算
- 移位運(yùn)算:<<和>>
- 左移,一位相當(dāng)于數(shù)字*2(加倍)
- 右移,相當(dāng)于數(shù)字/2
根據(jù)浮點(diǎn)數(shù)的結(jié)構(gòu)來看,浮點(diǎn)數(shù),明顯是達(dá)不到這樣的效果的。
大家拿起筆,思考一下,浮點(diǎn)數(shù)執(zhí)行,按位與&,按位或|,按位異或等運(yùn)算時(shí),是何種情況?。
3.2、浮點(diǎn)型數(shù)據(jù)轉(zhuǎn)換為整形數(shù)據(jù)時(shí),編譯器內(nèi)部做了什么樣的處理?
答:
#include <stdio.h> #include <stdlib.h> int main() { int a=1090; float b=1020.23; a=b; printf("a的值為%d:",a); return 0; }
看輸出結(jié)果:
看起來是似乎很合理?浮點(diǎn)數(shù)直接去掉小數(shù)部分,直接將自己的整數(shù)部分,賦值給了整形數(shù)據(jù).其實(shí)編譯器是先將浮點(diǎn)數(shù)值算出來,再截取整數(shù)部分截取給整形數(shù)據(jù)。
4、浮點(diǎn)數(shù)如何轉(zhuǎn)換為整型
浮點(diǎn)數(shù)可以通過舍去小數(shù)部分或四舍五入的方式轉(zhuǎn)換為整型。
舍去小數(shù)部分:
可以使用math.floor()函數(shù),該函數(shù)返回一個(gè)不大于浮點(diǎn)數(shù)的最大整數(shù)。例如:
num = 3.14 integer = math.floor(num) # 此時(shí)integer的值為3
四舍五入:
可以使用round()函數(shù),該函數(shù)返回一個(gè)最接近的整數(shù),如果有兩個(gè)整數(shù)與浮點(diǎn)數(shù)的距離相等,則返回偶數(shù)。例如:
num = 3.14 integer = round(num) # 此時(shí)integer的值為3
需要注意的是,轉(zhuǎn)換為整型可能會(huì)導(dǎo)致數(shù)據(jù)精度的損失。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
wchar_t,char,string,wstring之間的相互轉(zhuǎn)換
以下是對wchar_t,char,string,wstring之間的相互轉(zhuǎn)換進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-09-09Qt Design Studio創(chuàng)建工程的實(shí)現(xiàn)方法
Qt Design Studio它允許設(shè)計(jì)人員和開發(fā)人員使用通用的設(shè)計(jì)、開發(fā)、分析和調(diào)試工具在不同的開發(fā)平臺(tái)上共享一個(gè)項(xiàng)目,本文主要介紹了Qt Design Studio創(chuàng)建工程的實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下2022-05-05C/C++?實(shí)現(xiàn)動(dòng)態(tài)資源文件釋放的方法
當(dāng)我們開發(fā)Windows應(yīng)用程序時(shí),通常會(huì)涉及到使用資源(Resource)的情況。資源可以包括圖標(biāo)、位圖、字符串等,它們以二進(jìn)制形式嵌入到可執(zhí)行文件中,這篇文章主要介紹了C/C++?實(shí)現(xiàn)動(dòng)態(tài)資源文件釋放,需要的朋友可以參考下2023-12-12C語言模式實(shí)現(xiàn)C++繼承和多態(tài)的實(shí)例代碼
本篇文章主要介紹了C語言模式實(shí)現(xiàn)C++繼承和多態(tài)的實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07C語言實(shí)現(xiàn)游戲VIP停車場管理系統(tǒng)
這篇文章主要介紹了C語言實(shí)現(xiàn)游戲VIP停車場管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12C語言用函數(shù)實(shí)現(xiàn)電話簿管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言用函數(shù)實(shí)現(xiàn)電話簿管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12