系列文章目录
目录
前言
研究浮点型数字在内存中的存储方式,观察其与整型存储的方式有何不同。
一、浮点型和整型在内存中的存储方式是否相同
先来看一段代码及其运行结果
#define _CRT_SECURE_NO_WARNINGS
#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("num的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
return 0;
}
运行结果如下图:
这与我们所期望的值不同,但是什么原因导致的呢?
(整型与浮点型在内存中的存储方式不同)
二、浮点型在内存中的存储方式
1.浮点数存储规则
据国际标准IEEE(电子和电子工程协会)754,任意一个二进制浮点数V可用下面的形式表达
1> (-1)^S*M*2^E
2> (-1)^S表示符号位,当S=0,V=正数;S=1时V=负数
3> M代表有效数字,大于等于1,小于等于2;
4> 2^E表示指数位
以十进制小数5.5为例,其转换成二进制后表示为101.1,下图是二进制中各位所占的权重
可见,小数点右边的权重时从2的负一次方到2的负n次方减少的。
再以十进制数字5.5为例:
其转化为十进制后为101.1 ,用科学计数法表示后为1.011*2^2
再根据上方的浮点数表示方法可知 十进制数字5.5可表示为
(-1)^0 *1.011 *2^2
符号位S=0 M=1.011 E=2
对于32位的浮点数,最高的一位是符号位S,接着的8位时指数E,剩下的23位为有效数字M
对于64位的浮点数,最高的一位是符号位S,接着的11位时指数E,剩下的52位为有效数字M
2.对E进行分析
E的情况稍微有些复杂,E为一个无符号的整数
当E为8位时它的取值是0-255;如果E为11位,它的取值范围为0-2047,但是E用科学计数法表示,是可以出现负数的,所以在IEEE 754中规定存入内存时E的真实值必须再加上一个中间数,对于8位的E这个中间数位127;对于11位的E中间数为1023。
例如2^10的E为10,则32位浮点数中保存为10+127=137,用二进制表示为:10001001
继续以十进制数字5.5为例
32位浮点数存储下
(-1)^0 *1.011 *2^2
符号位S=0 M=1.011 E=2
E+127=129,129的二进制表示为10000001
则5.5表示为
0100 0000 1011 0000 0000 0000 0000 0000
转化为十六进制
4 0 b 0 0 0 0 0
究竟是不是这样存储的呢?
我们在Vs中进行调试:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
float f = 5.5;
return 0;
}
这是f在小端存储(何为小端存储?)下的存储形式,f应为40 b0 00 00存储,验证了我们的推测是正确的;
既然我们知道了浮点数是如何在内存中存储的,那我们也应该知道浮点数如何从内存中取出来
3.E从内存中取出
指数E从内存中取出还可以再分为三种情况:
1> E不为全0或不为全1
取法:指数E减去127(或1023),得到真实值,再将有效数字M前加上第一位的1;
2> E全为0
那么原来的指数加上127等于0;则真实值为-127,此时该浮点数接近0.
(-1)^s*0.xxxxxx*2^-127
所以规定浮点数的指数E等于1-127(或1-1023)为真实值,目有效数字M不再加上第一位的1,这样做的目的是为了表示正负0,以及接近于0的很小的数字。
3> E全为1
E中存储的数为255,则其真实值为128
(-1)^s*M*2^128,为很大的数字
此时这个数字为正无穷或负无穷(正负号取决于符号位s)
三、题解
有了上述的铺垫,文章开头的代码运行结果也能得到解释了
#define _CRT_SECURE_NO_WARNINGS
#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("num的值为:%d\n", n);
printf("*pFloat的值为:%f\n", *pFloat);
return 0;
}
先来看第二行输出的结果为什么为0.000000
32位机器下9的二进制序列为
00000000000000000000000000001001
但是是以%f的形式即以浮点数的形式打印的
0 00000000 00000000000000000001001
S E M
很明显E中全为0
这个数字可以表示为
(-1)^0*0.00000000000000000001001*2^-126,无限接近于0.
再来看看第三个为什么输出结果为1091567616
此时的num是用打印整型的方式去打印一个浮点型的数字
*pFloat=9.0
1001.0//二进制表示
1.001*2^3//浮点数
(-1)^0*1.001*2^3//浮点数
S=0 E=3 M=1.001
0 10000010 00100000000000000000000
此时这个二进制序列是以整型形式打印出来的,存储的是二进制的补码(有符号位)
观察该数字的十进制,与运行结果中一致,我们的疑惑得到解决。
创作不易留下你的赞吧2333333~