浮点数是用来表示小数的数据类型,我们可以通过以下代码看出浮点数和整形的在内存中的存储和读取是有差异的。
#include <stdio.h>
int main()
{
int a = 9;
float* p = (float*)&a;
printf("%d\n", a);
printf("%f\n", *p);
*p = 5.5;
printf("%d\n", a);
printf("%f\n", *p);
return 0;
}
那为什么会有这样的结果呢?
根据国际标准IEEE(电器和电子工程协会)754的规定,任意一个二进制浮点数V可以表示成下面的形式:(-1)^S*M*2^E。
我们可以这样理解这个标准,在十进制的情况下,每个数都可以用科学计数法来表示,比如100.5可以写成1.005*10^2,在二进制中,每个数也可以用科学计数法来表示,比如二进制100.5可以写成1.005*2*2^2,我们可以再乘上(-1)^S来表示正负,如果是正的,S=0,;如果是负的,S=1。 所以二进制浮点数V= (-1)^S*M*2^E。(-1)^S表示符号位,M表示有效数字,范围是1<=M<2,2^E表示指数位。
例如:5.5这个十进制的浮点数,写成二进制是101.0,101.0每一位的权重从左到右分别是1*2^2、0*2^ 1、1*2^0、0*2^(-1),因为是正数S=0,由于101.0=1.01*2^2, 所以S=1,M=1.01,E=2。
S 1 | E 8bit | M 23bit |
上图是32位的单精度浮点数的储存模型。
M的范围是1<=M<2,M=1.XXXXXX,IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以舍去1,只保留小数位,读取时,把1加上。
E的情况比较复杂,先是E不全为0或不全为1,比如0.1的E是-1,由于E存储时没正负之分,所以要加上 127,即-1+127=126,二进制是01111110,M=0,M前面补0补到23位, 00000000000000000000000,最后的结果是0 01111110 00000000000000000000000。
当E全为0 这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于 0的很小的数字;当E全为1 这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s。 .