1.浮点数家族:float ,double, long double
首先应明确,浮点数和整数的存储是不一样的。
先来看一个浮点数存储的例子:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
int n = 9;
float *pFloat = (float *)&n;//将n强制类型转换为float *型,赋值左右两边的类型要一致
printf("n的值为:%d\n", n);//9
printf("*pFloat的值为:%f\n", *pFloat);//0.000000
*pFloat = 9.0;
printf("num的值为:%d\n", n);//1091567616
printf("*pFloat的值为:%f\n", *pFloat);//9.000000
system("pause");
return 0;
}
四次输出的都不一样,为什么会是这样的结果呢?要解决这个问题就需要彻底搞懂浮点数在内存中到底是如何存储的。
我们知道任何数都有它的科学计数法,类比到这里,浮点数也有类似的表示:
(-1)^ SM*2^E =====>这里的s表示正负(1 负,0 正) M表示有效数字 2^E表示指数位
对于32位的浮点数(4字节),最高位为S占一个比特位,接下来是占8个比特位的E,剩下的23个比特位留给M(这里M只保存小数点后的部分)
知道了这些,解释上一段代码的结果也就不难了,下面来用一个具体的例子来理解浮点数在内存中的存储:
例如十进制的5.0
写成二进制是101.0,相当于1.01*2^2,那么s=0,M=1.01(实际存的话存的是01,存小数点后面的部分),E=2.
对于有效数字M和E,还有一些特殊的规定。1<=M<2,所以M在内存中只存小数点后面的部分。
2.指数 E
对于指数E也有很多要注意的地方,首先E为一个无符号整数(unsigned int )对于8位的E,取值范围是(0~ 255),对于11位的E,取值范围又是(0~2047)。但是科学计数法中E也可以是负数,所以内存时E的真实值要加上一个中间数,对于8位的E中间数为127,对于11位的E中间数是1023,
- 对于E不全为0或不全为1:指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的 1,带入科学计数法的公式就可以得到该浮点数。
*E全为0:表示接近于0的很小的数字。 - E全为1:如果有效数字M全为0,表示接近于0的很小的数或者无穷大的数(取决于符号位S)。
浮点数和整数在内存中的存储是有本质上的区别的。
最后让我们来解释一下开始的那个疑问,
9--------> 0000 0000 0000 0000 0000 0000 0000 1001
可以看出s=0(表示正数) E为全0 M=000 0000 0000 0000 0000 1001
带入公式得到:(-1)^0 * 0.00000000000000000001001 *2 ^(-146) 显然这是一个接近于0 的正数,所以用十进制表示就是0.000000
当浮点数为 9.0时:先用二进制表示(存)9.0--------> 1001.0 ——>(-1)^1.001 *2 ^ 3 ——> S=0,M=1.001,E=3+127=130
则在内存中的形式为:0 10000010 001 0000 0000 0000 0000 0000
这个数还原成十进制就是1091567616
至此,浮点数在内存中的存储基本上了解清楚,它和整数在内存中的存储也一样,这里需要知道浮点数的科学记数法的表示,知道浮点数怎么存在32个比特位中又是如何取出的。