上一篇文章中,我们了解了关于c语言中整型在内存中的存储,在这篇文章中,让我们一起学习浮点型数据是怎么样在内存中存储的。
引例
在正式学习浮点型在内存中的存储之前,让我们先来看一个引例,在学完之后,再来回头看这个引例,你是否有了新的理解?
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;
}
这个程序的结果是什么?来看看运行后的结果吧:
![](https://i-blog.csdnimg.cn/blog_migrate/8914f047d5298da3070215f1ccd381ee.png)
你是否感到疑惑不解?为什么*pFloat的值一会儿是0.0,一会儿又变成了9.0?为什么num的值如此之大?别着急,让我们带着疑问来学习浮点型在内存中的存储吧!
浮点型存储规则
根据国际标准IEEE 754,一个二进制浮点数可以表示成:
注意:
(-1)^s表示符号位,当s=0时,此浮点数为正;当s=1时,此浮点数为负。
M表示有效数字,。
2^E表示指数位,E可以为正数,负数或0,我们将在下面介绍E的详细划分。
IEEE 754规定:
对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
例1:
十进制:5.5
二进制:101.1
改写:(-1)^0 * 1.011 * 2^2
S:0
E:2
M:1.011
例2:
十进制:-10.0
二进制:-1010.0
改写:(-1)^1 * 1.01 * 2^3
S:1
E:3
M:1.01
符号位S
S只有1和0两种取值.
当浮点数为正时,S=0
当浮点数为负时,S=1
指数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。
除此之外,指数E还可以再分成三种情况:
E不全为0或1
这时,E的计算值减去127(或1023)得到E的真实值,再将有效数字M前加上第一位的1。
例子:
十进制:0.5
二进制:0.1
改写:(-1)^0 * 1 * 2^-1
S:0
E:-1 -1+127=126
二进制:01111110
M:1.0
去掉1 00000000000000000000000
浮点数存储:
0 01111110 00000000000000000000000
E全为0
这时,浮点数的指数E真实值等于1-127=-126(或者1-1023=-1022),此时有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
有效数字M
因为 1≤M<2 ,所以,所有M都可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。由于这个数的第一位总是1,因此,在保存时可以将1舍去,只保存后面的小数部分。
例如,保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。
这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,则可以保存24位有效数字。
引例解释
下面,让我们回到一开始的问题:
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;
}
为什么*pFloat的值一会儿是0.0,一会儿又变成了9.0?为什么num的值如此之大?
int n=9;
此时n是整型,内存中存储的是补码,正数的原反补码相同,因此内存中存的是:
00000000000000000000000000001001
但pFloat的类型是 float*,解引用后,*pFloat的类型是float,所以以浮点数的存储形式划分整型的n,如下:
0 00000000 00000000000000000001001
S:0
E:0
因为E全为0,所以M不+1
M:0.00000000000000000001001
最终:
(-1)^0 *0.00000000000000000001001* 2^0无限接近于0
所以输出0.000000
*pFloat = 9.0;
此时pFloat的类型是 float*,解引用后,*pFloat的类型是float,按浮点数存储方式存储因此内存中存的是:
1001.0
(-1)^0 *1.001* 2^3
S:0
M:1.001
处理后:0.001
E:3
处理后:3+127=130
0 10000010 00100000000000000000000
但num的类型是int,输出时将浮点数以整型的存储形式划分,如下:
二进制:01000001000100000000000000000000
十进制:1091567616