1.浮点数在内存中的存储
常⻅的浮点数:3.14159、1E10等,浮点数家族包括: float、double、long double 类型。 浮点数表⽰的范围: float.h 中定义
1.1 练习
#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.2 浮点数的存储
上⾯的代码中, num 和 *pFloat 在内存中明明是同⼀个数,为什么浮点数和整数的解读结果会差别 这么⼤?
要理解这个结果,⼀定要搞懂浮点数在计算机内部的表⽰⽅法。 根据国际标准IEEE(电⽓和电⼦⼯程协会)754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:
举例说明:
5.5(十进制)==101.1(二进制),转换为二进制的科学计数法为1.011*2的2次方
就相当于(-1)的0次方*1.011*10的2次方
所以:
S==0;
M==1.011;
E==2;
浮点数的存储,就是存储S,M,E相关的值 !!!!!!
IEEE754规定:
1.对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
float类型浮点数内存分配
2.对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
double类型浮点数内存分配
2.浮点数存的过程
1.EEE754对有效数字M和指数E,还有⼀些特别规定。
前⾯说过, 1≤M<2,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表⽰⼩数部分。 IEEE754规定,在计算机内部保存M时,默认这个数的第⼀位总是1,因此可以被舍去(即1不存储),只保存后⾯的 xxxxxx部分!!!!!!!!!!!!!!!!!!!!!!!!!!!。⽐如保存1.01的时候,只保存01,等到读取的时候,再把第⼀位的1加上去。
这样做的⽬ 的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第⼀位的1舍去以后,等于可以保 存24位有效数字。
2.⾄于指数E,情况就⽐较复杂
⾸先,E为⼀个⽆符号整数(unsigned int)
这意味着,1.如果E为8位,它的取值范围为0~255;2.如果E为11位,它的取值范围为0~2047。但是,我 们知道,科学计数法中的E是可以出现负数的
举例:
0.5(十进制)==0.1(二进制)==1.0*2的-1次方,这就产生了负数!!!!
所以IEEE754规定,存⼊内存时E的真实值必须再加上 ⼀个中间数:
1.对于8位的E,这个中间数是127;
2.对于11位的E,这个中间数是1023。
⽐如,2^10的E是 10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。
3.浮点数取的过程
指数E从内存中取出还可以再分成三种情况:
1.E不全为0或不全为1
这时,浮点数就采⽤下⾯的规则表⽰,
1.指数E的计算值减去127(或1023),得到真实值
2.再将有效 数字M前加上第⼀位的1。
⽐如:0.5的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其 阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位 00000000000000000000000,则其⼆进制表⽰形式为:
0 01111110 00000000000000000000000
2.E全为0
这时,浮点数的指数E等于1-127(或者1-1023)!!!!!!!!!!!!!!!即为真实值,有效数字M不再加上第⼀位的1,⽽是还 原为0.xxxxxx的⼩数。
这样做是为了表⽰±0,以及接近于0的很⼩的数字。!!!!!!!!!!!!!
0 00000000 00100000000000000000000
3.E全为1
这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);
1 0 11111111 00010000000000000000000
4.题目解析
#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.n在内存中的补码是
0000 0000 0000 0000 0000 0000 0000 1001
但是pfloat取数据的时候是按照浮点数的方式去取的,即
⾸先,将 9 的⼆进制序列按照浮点数的形式拆分,得到
1.第⼀位符号位s=0
2.后⾯8位的指数 E=00000000
3.最后23位的有效数字M=00000000000000000001001。
V=(-1)^0 × 0.00000000000000000001001×2^(-126)=1.001×2^(-146)
E全是0符合情况2,所以输出为0.0000000
2. pfloat存储9.0 即换算成科学计数法是:1.001×2^3
1.第⼀位的符号位S=0
2.有效数字M等于001后⾯再加20个0,凑满23位
3.指数E等于3+127=130, 即10000010
所以,写成⼆进制形式,应该是S+E+M,即
0 10000010 001 0000 0000 0000 0000 0000
这个32位的⼆进制数,被当做整数来解析的时候,就是整数在内存中的补码,原码正是 1091567616 。