C語言中的浮點(diǎn)數(shù)存儲詳解
1、首先明確一個概念
C語言中整形是按照二進(jìn)制存儲在內(nèi)存中,浮點(diǎn)型是按科學(xué)計(jì)數(shù)法存儲在內(nèi)存中(本質(zhì)上存儲的還是二進(jìn)制數(shù)據(jù)0和1)。
如果沒看懂這句話,沒關(guān)系!看完以下正文,你就會豁然開朗!并且預(yù)先提出兩個問題:
1)為什么浮點(diǎn)型不能執(zhí)行位運(yùn)算?
2)浮點(diǎn)型數(shù)據(jù)轉(zhuǎn)換為整形數(shù)據(jù)時,編譯器內(nèi)部做了什么樣的處理?
2、接下來,講解C語言中浮點(diǎn)型數(shù)存儲的規(guī)則
c語言中的浮點(diǎn)型有如下幾種 (float ,double ,longdouble),因?yàn)椴煌到y(tǒng)平臺下數(shù)據(jù)類型的長度會不一樣,這里我們統(tǒng)一在32位GCC編譯器下, float=4Byte,double=8個Byte
先定義
float num_1=10.5f; /* 這里有個小知識點(diǎn),很多編譯器中,如果10.5后面不加f(小寫),會默認(rèn)為存儲為double類型*/ double num_2 = 11.5
根據(jù)國際電器和電子工程協(xié)會,標(biāo)準(zhǔn)IEEE754規(guī)定,浮點(diǎn)數(shù)可以按照以下規(guī)則存儲
(-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語言存儲浮點(diǎn)型數(shù)據(jù)float時,會將內(nèi)存分為三個區(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。但是如果你按上述來寫,肯定是錯誤的。浮點(diǎn)數(shù)存儲時,還要遵守一定的轉(zhuǎn)換方式:轉(zhuǎn)換規(guī)則如下(也是很重要的一個知識點(diǎn))
(規(guī)則1)1<=M<2。IEEE 754規(guī)定 M只存儲小數(shù)部分,于是10.5只會存儲0101,系統(tǒng)會默認(rèn)最高位為1(。
(規(guī)則2)而E,存儲時:
- float類型數(shù)據(jù),存儲值=E+127.
- double類型數(shù)據(jù),存儲值=E+1023.
首先得明確是一個無符號數(shù),10.5=1.0101*2^3,E=3,二進(jìn)制表示為 0000 0011。IEEE754規(guī)定了。對于32bit長度的float類型。E需要加上127,在此得到的數(shù),再存儲到內(nèi)存中去,我們把這個值叫做E的存儲值。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),下面會介紹。
2.2、問:十進(jìn)制小數(shù)0.5該如何存儲?
轉(zhuǎn)換為二進(jìn)制科學(xué)計(jì)數(shù)法1*2^-1。如果我們E不做處理。
將會有如下問題,s=0,沒有問題,E=-1,E是無符號數(shù),不能顯示為-1。M存儲的是小數(shù)部分,全部存儲為0。
故:為了解決E無法表示負(fù)數(shù)的問題,才引入了E+127(Float),和E+1023(double)。為了描述方便,下面統(tǒng)一以float類型為例,當(dāng)E存儲值<127時,認(rèn)定E為負(fù)數(shù),如E存儲值為125,則E的實(shí)際值為-2。當(dāng)E的存儲值>127時,E的真實(shí)值為正數(shù),130=3。以此類推。。。。
故,本質(zhì)上E存儲時需要+127或+1023是為了解決浮點(diǎn)數(shù),(-1,1)注意是不包含邊界數(shù)的關(guān)系,的存儲問題。
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
這時,浮點(diǎn)數(shù)就采用下面的規(guī)則表示,即指數(shù)E的計(jì)算值減去127(或1023),得到真實(shí)值,再將 有效數(shù)字M前加上第一位的1。
E全為0
- 這時,浮點(diǎn)數(shù)的指數(shù)E等于1-127(或者1-1023)即為真實(shí)值, 有效數(shù)字M不再加上第一位的1,而是還原為0.xxxxxx的小數(shù)。這樣做是為了表示±0,以及接近于 0的很小的數(shù)字。
E全為1
- 這時,如果有效數(shù)字M全為0,表示±無窮大(正負(fù)取決于符號位s);
2.3 浮點(diǎn)數(shù)存儲時的誤差
float Val_1=0.6f;
此時我們算一下,常量0.6f是如何存儲的。使用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ù)存儲時,是無法準(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.
存儲時:
S=0; E=-1+126=125; M=001
3、回答一開始提出的兩個問題
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)算時,是何種情況?。
3.2、浮點(diǎn)型數(shù)據(jù)轉(zhuǎn)換為整形數(shù)據(jù)時,編譯器內(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ù)返回一個不大于浮點(diǎn)數(shù)的最大整數(shù)。例如:
num = 3.14 integer = math.floor(num) # 此時integer的值為3
四舍五入:
可以使用round()函數(shù),該函數(shù)返回一個最接近的整數(shù),如果有兩個整數(shù)與浮點(diǎn)數(shù)的距離相等,則返回偶數(shù)。例如:
num = 3.14 integer = round(num) # 此時integer的值為3
需要注意的是,轉(zhuǎn)換為整型可能會導(dǎo)致數(shù)據(jù)精度的損失。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
wchar_t,char,string,wstring之間的相互轉(zhuǎn)換
以下是對wchar_t,char,string,wstring之間的相互轉(zhuǎn)換進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-09-09
Qt Design Studio創(chuàng)建工程的實(shí)現(xiàn)方法
Qt Design Studio它允許設(shè)計(jì)人員和開發(fā)人員使用通用的設(shè)計(jì)、開發(fā)、分析和調(diào)試工具在不同的開發(fā)平臺上共享一個項(xiàng)目,本文主要介紹了Qt Design Studio創(chuàng)建工程的實(shí)現(xiàn)方法,具有一定的參考價值,感興趣的可以了解一下2022-05-05
C/C++?實(shí)現(xiàn)動態(tài)資源文件釋放的方法
當(dāng)我們開發(fā)Windows應(yīng)用程序時,通常會涉及到使用資源(Resource)的情況。資源可以包括圖標(biāo)、位圖、字符串等,它們以二進(jìn)制形式嵌入到可執(zhí)行文件中,這篇文章主要介紹了C/C++?實(shí)現(xiàn)動態(tài)資源文件釋放,需要的朋友可以參考下2023-12-12
C語言模式實(shí)現(xiàn)C++繼承和多態(tài)的實(shí)例代碼
本篇文章主要介紹了C語言模式實(shí)現(xiàn)C++繼承和多態(tài)的實(shí)例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07
C語言實(shí)現(xiàn)游戲VIP停車場管理系統(tǒng)
這篇文章主要介紹了C語言實(shí)現(xiàn)游戲VIP停車場管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12
C語言用函數(shù)實(shí)現(xiàn)電話簿管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言用函數(shù)實(shí)現(xiàn)電話簿管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12

