给大家分享一句我很喜欢我话:
知不足而奋进,望远山而前行!!!
铁铁们,成功的路上必然是孤独且艰难的,但是我们不可以放弃,远山就在前方,但我们能力仍然不足,所有我们更要奋进前行!!!
今天我们更新了xxxxxxx内容,
🎉 欢迎大家关注🔍点赞👍收藏⭐️留言📝
一、问题引入
在文章开始,我们先来看一段代码来:
int main()
{
int n = 9;
float* pn = (float*) & n;
printf("%d\n", n); //输出9
printf("%f\n", *pn); //输出0.000000
float n1 = 9.0;
int* pn1 = (int*)&n1;
printf("%d\n", *pn1);//输出1091567616
return 0;
}
大家认为这段代码输出什么,三个printf应该分别输出9、9.000000、9,但运行结果现然与预期不符,为什么?
这里,就设计到了浮点型数据和整型数据之间存储方式的差别。对于第一个printf,直接打印整型的n,显然没有问题。但对于第二个printf,解应用指向n的指针pn,pn是浮点型指针,对其解应用并打印,是以浮点型数据存储方式的视角去读取数据。而对于第三个printf,n1以浮点型数据的存储方式存入内存,以整型数据的视角解应用指向n1的指针pn1。这就解释了为什么实际结果与预期结果有很大的差异。
二、两类浮点型数据(float、double)在内存中的存储方式
2.1两类浮点型数据的存储模型
根据IEEE754标准规定,浮点型数据的存储和读取按照公式:
- Value为浮点型数据的二进制值
- S表示浮点型数据的正负,0表示正,1表示负
- M为位于位于区间
的小数
- E表示为指数部分
举例说明具体应用方式:对于float n = 10.5,其二进制表示为(00....00001010.1),可理解为,其中S=0,M=1.0101,E=3。
2.2float类型和double类型的储存模型
下面为单精度浮点型数据float的存储模型,符号位S存在最高位,占用1bit内存,指数位E占用8bit内存,M占用23bit内存。
下面为双精度浮点型数据double在内存中的存储模型,符号位S占用1bit内存,指数为E占用11bit的内存,M占用52bit的内存。
2.3对浮点型数据存储模型的详细解读
符号位表示浮点型数据的正负,0表示正数,1表示负数,如10.5的符号位S为0,-10.5的符号位S为1。
指数位E即2的次方数,如 float n = 10.5,可以表示为。这里,E = 3。但是,IEEE754标准中规定E为一个无符号整型,而现实中科学计数法指数位E可能为负数,因此,这里引入了中间值的概念。对于单精度浮点型数据float,E的中间值为127,对于双精度浮点型数据double,E的中间值为1023。在对E进行存储时,需要将其真实值加上中间值后再存入内存。如,10.5的指数位真实值E = 3,则存入内存内存应为E = 3 + 127(中间值) = 130。再比如,真实指数位E = -2时,存入内存应为 E = -2 + 127 =125。
M位可理解为有效数据,其取值范围是,因为M小数点前面的数永远为1,为了增加浮点型数据的精度及可表示的数据的范围,IEEE754标准规定M在内存中只存储小数点后边的位,如float n =10.5 表示为
,M = 1.0101,存入内存时舍去小数点前面的1,仅存入0101。
三、引入问题的解答
第二章展示的代码的第二个printf打印结果为0.000000,是因为其以浮点数的视角去读取内存中的数据。图4.1 展示了整型数据 int n = 9 在内存中的存储形式,若以浮点型数据的视角去读数,则,,E的二进制位全部为0,由3.5.2中提到的知识,E的二进制位全为0时表示为一个无穷小的数据,且以%f 的形式打印数据精确度为小数点后6为,故打印0.000000。
第三个printf打印的数据为1091567616,一个非常大的数据。这是因为 n1 = 9.0 以浮点型数据的存储方式存入到了内存中(存储方式如图4.2所示),但在读取并打印这个数据的时候,却是对一个整型指针进行解应用,将9.0以整型数据的视角进行读取和打印。
故打印结果为:
四、总结
本文详细介绍了单精度浮点型数据和双精度浮点型数据在内存中存储的方法,给出了浮点型数据的存储模型和读取模型,并以案例的形式进行了介绍。浮点型数据可表示为:。其中为符号位,在内存中占用8bit的空间;为指数位,在内存中占8bit(float类型数据)或16bit(double类型数据)的内存空间;表示有效数组在内存中占23bit(float类型数据)或52bit(double类型数据)的内存空间。