目录
前言
一、引例
二、浮点型在内存中的存储
三、浮点数在内存中的存和取过程
1.浮点数的存储过程
2.浮点数的取过程
四、引例解析
总结
前言
想知道浮点数在内存中是如何存储的吗,本文就告诉你答案,虽然一般情况题目还是面试涉及到浮点数在内存中的存储很少,但是了解其存储机制有利于加深我们对C语言的理解,修炼我们的内功。
❤️感谢支持,点赞关注不迷路❤️
一、引例
我们看以下代码:
#include <stdio.h>int main()
{int n = 9;float* pFloat = (float*)&n;printf("n的值为:%d\n", n);printf("pFloat的值为:%f\n", *pFloat);*pFloat = 9.0;printf("n的值为:%d\n", n);printf("pFloat的值为:%f\n", *pFloat);return 0;
}
运行结果:
发现:我们观察到,将整数9以浮点型打印时为0.000000,将浮点型9.0以整形打印时是一个较大的数字。这一点就可以说明整形与浮点型在内存中的存储形式是不同的。
二、浮点型在内存中的存储
我们知道整数在内存中是以补码的形式储存的,那么浮点数是怎么存储的呢?
根据国际标准IEEE(电气和电子工程协会)754,任意一个⼆进制浮点数V可以表示成下面的形式:
举例:浮点数5.5用以上形式如何表示:
- 首先5.5翻译成二进制为 101.1。
- 然后就可以改写成以下形式:
- 这时候,M就是1.011,E就是2,S自然为0
然后,只需要将S、M、E这三个数存储到内存中,就可以储存一个浮点数了,那么这三个数是如何在内存中存放的呢?
IEEE 754规定:
- 对于32位的浮点数(float),最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数
- 字M 对于64位的浮点数(double),最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
注意:不管怎样,内存中存储的还是补码
三、浮点数在内存中的存和取过程
1.浮点数的存储过程
IEEE 754对有效数字M和指数E,还有一些特别规定。
M的存储过程:前面用101.1举例,可以写成类似科学计数法的形式。1<=M<2,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表表示小数部分。那么就有以下规定:
IEEE 754规定,在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去,只保存后面的 xxxxxx部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保存24位有效数字。
E的存储过程:指数E,情况就比较复杂首先,E为一个无符号整数(unsigned int),这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的。E又是无符号整数,所以规定:
IEEE754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是 10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
举例:浮点数(float)5.5,二进制位:101,1
- S:0,E:2,M:001
- 但是E存入内存时(float)要加上127等于129
- 结果就是 0 10000001 01100000000000000000000
- 注意:M后不够是补0的
- 0100 0000 1011 0000 0000 0000 0000 0000翻译为16进制为0x40 b0 00 00
- 然后我们在VS中调试观察,验证以下
- 因为VS是小端存储,所以是倒着存,结果一致
2.浮点数的取过程
这里主要是指数E从内存中取出还可以再分成三种情况:
1.E不全为0或不全为1(和上面举例一样,正常取)
这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
比如:0.5的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为1.0*2^(-1),其阶码为-1+127(中间值)=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位 00000000000000000000000,则其二进制表示形式为:
0 01111110 00000000000000000000
2.E全为0(特殊情况)
这时,浮点数的指数 E 等于1-127(或者1-1023)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
比如1.0*2的负127次方,这个数无限接近于0,所以M读取时不再加上1,并且指数读取时是减126而不是127,因为M的整数位1被移到了小数部位,所以内存中为0 00000000 00000000000000000000000,读取时就是0.000000
3.E全为1(特殊情况)
这时,浮点数指数 E 等于128,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
我们可以简单算一下,2的32次方大约42亿,那么4个42移相乘,那数字将会非常大。
四、引例解析
引例中的结果:
我们来一步一步分析:
- 首先 int n = 9,它在内存中的补码为:00000000 00000000 00000000 00001001。以%d打印肯定是9没毛病。
- 然后通过指针把它当做浮点型打印,这时编译器就会将n的补码以浮点数的格式进行读取,float为32个比特位,可以写成0 00000000 00000000000000000001001。
- 这里 E 的部分全为0,对应了上文第二种情况,E将无限接近于0,读取出来就是,0.9*2的负126次方,等于0.00000...9,而编译器默认打印小数点后6位,因此结果才为0.000000
- 通过指针将n的空间存的值修改为9.0,而9.0将会以32位浮点型的格式存储到内存中,9.0翻译为二进制为:1001.0,变为科学计数法为:1.001*2^3,那么S:0,E:3,M:1.001
- E存入内存要加上127等于130,二进制为:10000010,因此9.0存入内存的二进制为:0 10000010 00100000000000000000000
- 将 01000001000100000000000000000000以整形的格式读取时就为:
- 以浮点型%f读取就是正常9.0
所以我们在拿到一个数据时,非特殊一定要以正确的格式读取,否则就不是你想要的数字
总结
以上就是本文的全部内容,希望对你有所帮助。