目录
学完整数在内存中的存储,大家一定很好奇浮点数在内存中是如何存储的,本文将介绍浮点数在内存中是如何存储的,并举例说明其存储规则。
1 常见的浮点数
5.00
3e10
3.1415926
浮点数类型有:
float, double, long double
浮点数表示的范围:C语言中由 float.h 定义
2 一个小例子
int main()
{
int a = 15;
float* pa = (float*)&a;
printf("a = %d\n", a);
printf("*pa = %f\n", *pa);
*pa = 15.25;
printf("a = %d\n", a);
printf("*pa = %f\n", *pa);
return 0;
}
输出的结果如下
下面将详细介绍浮点数存储规则,然后分析上述代码
3 浮点数存储规则
根据相关国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数 V 可以表示成下面的形式:
(-1)^S × M × 2^E
(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数
M表示有效数字,大于等于1,小于2
2^E表示指数位
什么意思呢,举例说明,一个十进制数字15.25,其中的15转换成二进制数是
00000000 00000000 00000000 00001111
0.25转换成二进制数是
01000000 ...
第一位的权重为2^(-1),第二位的权重为2^(-2),0.25=2^(-2),所以写成二进制是如上的二进制数
两个数合起来就是1111.01,相当于(-1)^0 × 1.11101 × 2^3,那么 S = 0,M = 1.11101,E = 3
IEEE 754规定:
对于32位浮点数,最高1位是存放符号位S,紧接着的8位是指数E,剩下的23位是有效数字M
对于64位浮点数,最高1位是存放符号位S,紧接着的11位是指数E,剩下的52位是有效数字M
IEEE 754对有效数字M和指数E,还有一些特别规定。
对于有效数字M
因为数据是以二进制的形式存放在内存中的,所以M的每一位非0即1
若首位为0,则小数点向后移动k位,指数E = k,直到首位为1,所以才会有1≤M<2
此时,M的首位必为1,那么就不用再额外花费空间存储这个1了,只用保存小数点后面的数字
将第一位的1舍去以后,单精度浮点数可以保存24位有效数字
指数E的存储
首先,E在内存里是一个无符号的整数
如果E为8位,则取值范围为0~255;如果E为11位,则取值范围为0~2047
但是实际上科学计数法的E是可以出现负数的,比如0.125,它等于
0.001
(-1)^0 × 1.0 × 2^(-3)
所以 IEEE 754 规定
存入内存时E的真实值必须再加上一个中间数
对于8位的E,这个中间数是127
对于11位的E,这个中间数是1023
因此,若使用 float 存放数据,则科学计数法中E为-127~128时才可以正常存储
所以E = -3,保存成32位浮点数时,需保存 -3 + 127 = 124,即1111100
指数E的读取还可分成三种情况
-
E不全为0或1
这时,指数E的真实值等于内存中的值转换成十进制,然后减去中间值127(或1023),得到真实值,再将有效数字M前面加上第一位的1
-
E全为0
这时,根据尾数M的不同可以分为两种情况:
有效数字M为0:表示浮点0
有效数字M不为0:那么E = 1-127 = -126(或者1-1023)有效数字M不再加上第一位的1,而是还原为形如0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
-
E全为1
有效数字M为0:根据符号位S表示±无穷大
有效数字M不为0:表示NaN(Not a Number)
4 解释前面的例子
int main()
{
int a = 15;
float* pa = (float*)&a;
printf("a = %d\n", a);
printf("*pa = %f\n", *pa);
*pa = 15.25;
printf("a = %d\n", a);
printf("*pa = %f\n", *pa);
return 0;
}
现在,让我们回到一开始的问题
15的补码是00000000 00000000 00000000 00001111
站在浮点数的角度,S=0,E= -126,M= 0000000 00000000 00001111
这是 一个非常小的数字,保留6位小数的话*pa = 0.000000
*pa = 15.25;
而上面这行代码是把浮点数15.25赋给了*pa
但 a 的类型是 int,它会站在整型的角度计算15.25
15.25 -> 1111.01 = (-1)^0 × 1.11101 × 2^3 -> 0 10000010 11101000 00000000 0000000
直接将上面的二进制数换算成十进制数就是 a 的值