浮点数家族的三个类型有float,double,long double,他们在内存中的存储方式和整型有着本质上的区别。
首先我们通过一个例子来引出悬念:
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;
}
如果我们在不知道浮点型在内存中的存储细节时,我们不难得到以下错误的结果:
9 9.000000 9 9.0000
但是真正的结果是多少?让我们看下边这张图:
错的有点离谱,下面开始分析:
浮点数在内存中的存储是按照公式:(-1)^S*M*2^E 来存储的,
(-1)^S表示的是符号位
M表示有效数字
E表示指数位
在32位机器上,第1位表示符号位,即(-1)^S;第2~9位表示指数位,也就是E;后面的23位表示的是有效数字M。而64位机器上,第1位表示符号位,第2~12位表示指数位,剩下52位表示有效数字。
符号位用0和1表示,浮点数为正则是1,反之则为0.
指数位大小,相当于将一个浮点数的二进制形式移动小数点直到范围为1~2时所移动的位数加上一个补偿数,例如十进制的3.25,变为二进制得到11.01,转换为科学计数法的形式就是1.101*2^1,这里的1要加上一个补偿数,在32位计算机上加127,在64位计算机上加1023,这里的E以32位计算机为例,值为1+127得到128。
M就是浮点数二进制形式经过科学计数法表示得到的有效数字,也就是上面例子的1.101,但是在内存中,是不存储首位整数位的1的,计算机默认该整数位的值为1,不存储,在读取时再将1加上去.这样就可以多保存一位小数位,提高了精度.
知道了浮点数在内存中的存储,我们试着理解最上面的题:
首先创建一个n的整型变量:
int n=9
我们以%d打印一点得到9;
printf("*pFloat=%f\n", *pFloat);
当我们创建一个float类型的指针变量*pFloat,然后将地址n处的值强制转换为float类型存储在该变量中,以%f打印时:
00000000000000000000000000001001
指数位全为0,当E全为0时,代表该数无限趋近于0,因此打印得到结果为0.000000
*pFloat = 9.0;
printf("num=%d\n", n);
我们将*pFloat的值改为9.0,此时在内存中是按照浮点数的方法存储的,也就是
01000001000100000000000000000000
我们以整型%d打印,该值也就是1091567616
printf("*pFloat=%f\n", *pFloat);
最后,我们以浮点型%f打印浮点数,就正确得到了9.000000
浮点型的主要部分就是这样,这里有几种特殊情况还需要加以说明:
当E为全0时,代表该浮点数趋近于无穷小
当E为全1时,代表该浮点数趋近于+/-无穷大.
如果该文章对你有所帮助,还请点赞支持一下.