C語言中的浮點數存儲詳解
1、首先明確一個概念
C語言中整形是按照二進制存儲在內存中,浮點型是按科學計數法存儲在內存中(本質上存儲的還是二進制數據0和1)。
如果沒看懂這句話,沒關系!看完以下正文,你就會豁然開朗!并且預先提出兩個問題:
1)為什么浮點型不能執(zhí)行位運算?
2)浮點型數據轉換為整形數據時,編譯器內部做了什么樣的處理?
2、接下來,講解C語言中浮點型數存儲的規(guī)則
c語言中的浮點型有如下幾種 (float ,double ,longdouble),因為不同系統平臺下數據類型的長度會不一樣,這里我們統一在32位GCC編譯器下, float=4Byte,double=8個Byte
先定義
float num_1=10.5f; /* 這里有個小知識點,很多編譯器中,如果10.5后面不加f(小寫),會默認為存儲為double類型*/ double num_2 = 11.5
根據國際電器和電子工程協會,標準IEEE754規(guī)定,浮點數可以按照以下規(guī)則存儲
(-1)^S*M*2^E
2.1、可以將上述公式分為兩部分來看
(-1)^S是確定數字是整數還是負數。M*2^E確定的數字絕對值的大小。
- 這里的M必須是二進制數。有些資料把M叫做尾數
- S必須是整數1,或整數0。有些資料把S叫做數符
- E也必須是>=0的整數。有些資料把E叫做階碼
結合圖形來看:

C語言存儲浮點型數據float時,會將內存分為三個區(qū)域。結合實例我們來看
float num_1=10.5,先轉換為IEEE754格式,首先該數為正數故s=0;(-1)^0=0,符號位=0,表示正數。
- 第1步:在把10.5轉換為科學計數法 1.05*10^1,
- 第2步:再把10.5二進制格式,其中M要為二進制數據,dec(10.5)=bin(1010.1)
- 第3步:二進制寫成科學計數法10.5=1010.1*2^0 = 1.0101*2^3。
10.5為正數于是 31符號位S=0、E=3 =0000 0011 。有效數字M=1.0101。但是如果你按上述來寫,肯定是錯誤的。浮點數存儲時,還要遵守一定的轉換方式:轉換規(guī)則如下(也是很重要的一個知識點)
(規(guī)則1)1<=M<2。IEEE 754規(guī)定 M只存儲小數部分,于是10.5只會存儲0101,系統會默認最高位為1(。
(規(guī)則2)而E,存儲時:
- float類型數據,存儲值=E+127.
- double類型數據,存儲值=E+1023.
首先得明確是一個無符號數,10.5=1.0101*2^3,E=3,二進制表示為 0000 0011。IEEE754規(guī)定了。對于32bit長度的float類型。E需要加上127,在此得到的數,再存儲到內存中去,我們把這個值叫做E的存儲值。3+127=129=1000 0010。double類型,應該加上1023。至于為什么,后面細說。

M的0101,應該左移到22-19bit位處
于是10.5的正確格式應該是上圖所示的格式。
至于E為什么要+127(float)+1023(double),下面會介紹。
2.2、問:十進制小數0.5該如何存儲?
轉換為二進制科學計數法1*2^-1。如果我們E不做處理。
將會有如下問題,s=0,沒有問題,E=-1,E是無符號數,不能顯示為-1。M存儲的是小數部分,全部存儲為0。
故:為了解決E無法表示負數的問題,才引入了E+127(Float),和E+1023(double)。為了描述方便,下面統一以float類型為例,當E存儲值<127時,認定E為負數,如E存儲值為125,則E的實際值為-2。當E的存儲值>127時,E的真實值為正數,130=3。以此類推。。。。
故,本質上E存儲時需要+127或+1023是為了解決浮點數,(-1,1)注意是不包含邊界數的關系,的存儲問題。
E不全為0或不全為1
比如:
- 0.5(1/2)的二進制形式為0.1,由于規(guī)定正數部分必須為1,即將小數點右移1位,則為 1.0*2^(-1),其E為-1+127=126,表示為:
- 01111110,而尾數1.0去掉整數部分為0,補齊0到23位00000000000000000000000,則其二進 制表示形式為:
- 0 01111110 000000000000000000000001
另外還有兩種比較特殊的情況,E全為0和E全為1
這時,浮點數就采用下面的規(guī)則表示,即指數E的計算值減去127(或1023),得到真實值,再將 有效數字M前加上第一位的1。
E全為0
- 這時,浮點數的指數E等于1-127(或者1-1023)即為真實值, 有效數字M不再加上第一位的1,而是還原為0.xxxxxx的小數。這樣做是為了表示±0,以及接近于 0的很小的數字。
E全為1
- 這時,如果有效數字M全為0,表示±無窮大(正負取決于符號位s);
2.3 浮點數存儲時的誤差
float Val_1=0.6f;
此時我們算一下,常量0.6f是如何存儲的。使用2進制來表示的話,我們知道2^-1=0.5、2^-2=0.25、2^-3=0.125、2^-4=0.0625......
故我們使用0.1b=0.5,還需要表示出10進制的小數0.1。從上面的例子也可以看出,實際上浮點數存儲時,是無法準確的表示出0.1的。所以只能采取一種無限逼近的方法,0.6的二進制表示是0.1001100110011...(無限循環(huán)),如果需要有限位數的表示,可以根據需要選擇適當的位數進行截取。例如,取4位小數,則表示為0.1001。使用二進制科學計數法為1.001*2^-1.
存儲時:
S=0; E=-1+126=125; M=001
3、回答一開始提出的兩個問題
3.1、為什么浮點數不能執(zhí)行位運算;
答:整形執(zhí)行位運算,準確的來說是無符號整形,才能執(zhí)行位運算
- 移位運算:<<和>>
- 左移,一位相當于數字*2(加倍)
- 右移,相當于數字/2
根據浮點數的結構來看,浮點數,明顯是達不到這樣的效果的。
大家拿起筆,思考一下,浮點數執(zhí)行,按位與&,按位或|,按位異或等運算時,是何種情況?。
3.2、浮點型數據轉換為整形數據時,編譯器內部做了什么樣的處理?
答:
#include <stdio.h>
#include <stdlib.h>
int main()
{ int a=1090;
float b=1020.23;
a=b;
printf("a的值為%d:",a);
return 0;
}看輸出結果:

看起來是似乎很合理?浮點數直接去掉小數部分,直接將自己的整數部分,賦值給了整形數據.其實編譯器是先將浮點數值算出來,再截取整數部分截取給整形數據。
4、浮點數如何轉換為整型
浮點數可以通過舍去小數部分或四舍五入的方式轉換為整型。
舍去小數部分:
可以使用math.floor()函數,該函數返回一個不大于浮點數的最大整數。例如:
num = 3.14 integer = math.floor(num) # 此時integer的值為3
四舍五入:
可以使用round()函數,該函數返回一個最接近的整數,如果有兩個整數與浮點數的距離相等,則返回偶數。例如:
num = 3.14 integer = round(num) # 此時integer的值為3
需要注意的是,轉換為整型可能會導致數據精度的損失。
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
wchar_t,char,string,wstring之間的相互轉換
以下是對wchar_t,char,string,wstring之間的相互轉換進行了詳細的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-09-09
Qt Design Studio創(chuàng)建工程的實現方法
Qt Design Studio它允許設計人員和開發(fā)人員使用通用的設計、開發(fā)、分析和調試工具在不同的開發(fā)平臺上共享一個項目,本文主要介紹了Qt Design Studio創(chuàng)建工程的實現方法,具有一定的參考價值,感興趣的可以了解一下2022-05-05

