C語言float double的記憶體表示

2021-10-17 23:11:38 字數 2699 閱讀 5411

在記憶體中,小數是以指數形式存在的。float、double 在記憶體中的形式如下所示:

小數在被儲存到記憶體前,首先轉換為下面的形式:

a × 2 n

其中 a 為尾數,是二進位制形式,且 1 ≤ a < 2;n 為指數,是十進位制形式。

例如對於 19.625,整數部分的二進位制形式為:

19 = 1×24 + 0×23 + 0×22 + 1×21 + 1×20 = 10011

小數部分的二進位制形式為:

0.625 = 1×2-1 + 0×2-2 + 1×2-3 = 101

將整數部分和小數部分合併在一起:

19.625 = 10011.101

再將小數點向左移動4位:

19.625 = 10011.101 = 1.0011101×24

此時尾數為 1.0011101,指數為 4。

所有的小數被轉換成指數形式後,尾數的整數部分都為1,無需在記憶體中提現出來,所以乾脆將其截去,只把小數點後面的二進位制放入記憶體中的尾數部分(23bits)。對於 1.0011101,尾數部分就是 0011101。

c語言把整數作為定點數,而把小數作為浮點數。定點數必須轉換為補碼再寫入記憶體,浮點數沒有這個過程,直接寫入原碼。小數被轉換成指數形式後,指數有正有負,在記憶體中不但要能表現其值,還要能表現其正負。而指數是以原碼形式儲存的,沒有符號位,所以要設計乙個巧妙的辦法來區分正負。

對於 float,指數占用8bits,能表示從 0~255 的值,取其中間值 127,指數在寫入記憶體前先加上127,讀取時再減去127,正數負數就顯而易見了。19.625 轉換後的指數為 4,4+127 = 131 = 1000 0011。

綜上所述,float 型別的 19.625 在記憶體中的值為:0 - 10000011 - 001 1101 0000 0000 0000 0000。

下面我們使用**來驗證一下:

#include 

#include

int main()

fp_single;

float a = 19.625;

fp_single* p = (fp_single*)&a;

printf("%d, %#x, %#x\n", p->nsign, p->nexponent-127, p->nmantissa);

system("pause");

return 0;

}執行結果:

0, 0x4, 0x1d0000

c語言不能直接輸出二進位制形式,一般輸出十六進製制即可,十六進製制能夠很方便地轉換成二進位制。
精度指測量值與真實值的接近程度,在c語言中表現為輸出值和真實值的接近程度。

float 和 double 的精度是由尾數的位數決定。記憶體中的尾數只儲存了小數點後面的部分,其整數部分始終是乙個隱含著的「1「,它是不變的,不會對精度造成影響。

float:2^23 = 8388608,一共七位,這意味著最多能有7位有效數字,但絕對能保證的為6位,也即 float 的精度為 6~7 位有效數字。

double:2^52 = 4503599627370496,一共16位,同理,double 的精度為 15~16 位。

float 和 double 在記憶體中的指數和尾數的位數都是有限的,小數過大或過小都會發生溢位。float 的取值範圍為 -2^128 ~ +2^128,也即 -3.40e+38 ~ +3.40e+38;double 的取值範圍為 -2^1024 ~ +2^1024,也即 -1.79e+308 ~ +1.79e+308。

當小數的尾數部分過長時,多出的位數就會被直接截去,這時儲存的就不是小數的真實值,而是乙個近似值。在《c語言中的浮點數(float,double)》一節的示例中,我們看到 128.101 的輸出結果就是乙個近似值。

128.101 轉換成二進位制為 10000000.0001100111011011001000101101,向左移動7位後為 1.00000000001100111011011001000101101,由此可見,尾數部分為 000 0000 0001 1001 1101 1011 001000101101,將多出的二進位制截去後為 000 0000 0001 1001 1101 1011。下面的**有力地證明了這一點:

#include 

#include

int main()

fp_single;

float a = 128.101f;

fp_single* p = (fp_single*)&a;

printf("%f\n", a);

printf("%d, %#x, %#x\n", p->nsign, p->nexponent-127, p->nmantissa);

system("pause");

return 0;

}執行結果:

128.100998

0, 0x7, 0x19db

最後對 float 和 double 做一下總結:

型別說明符

位元數(位元組數)

有效數字

數的範圍

float

32(4)

6~7-3.40e+38 ~ +3.40e+38

double

64(8)

15~16

-1.79e+308 ~ +1.79e+308

float double 的儲存方式

float 和 double 的表示法 都是二進位制的科學表示法 mantissa 2 exponent mantissa 尾數,exponent 指數,均使用二進位制表示 float 浮點型 在記憶體中佔4個位元組 byte 即32位 bit 儲存方式如下 1 bit 符號位 8 bit 指數字 ...

float,double在記憶體中的儲存方式

將17.625換算成 float型。首先,將17.625換算成二進位制位 10001.101 0.625 0.5 0.125,0.5即 1 2,0.125即 1 8 如果不會將小數部分轉換成二進位制,請參考其他書籍。再將 10001.101 向右移,直到小數點前只剩一位 成了 1.0001101 x...

用float double作為中轉型別的「雷區」

n由於lua用double作為number型別的底層資料中轉型別。而實際應用中多以int型別作為函式呼叫的引數 特別是c實現的api 因而,double int unsigend int之間的數值轉換在接入lua的專案中應用十分廣泛。實際專案發現,double int unsigend int之間的...