浮点型数据在内存中的存储

281 阅读3分钟

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;
}

最终输出结果:

在这里插入图片描述

最终的结果可能出乎大家的预料。 要想知道为什么最终输出的结果会是这个样子就得弄懂浮点型数据在内存中是怎样存储的。

2、浮点型数据在内存中的存储规则

浮点型数据在内存中的存储形式是由国际标准IEEE754规定的。

这里会有同学好奇IEEE754是什么,这里我提供了百度百科的解释: 在这里插入图片描述 点击链接了解更多link

该标准规定:任意一个二进制浮点数V可以表示成下面的形式:

  • (-1) ^S * M * 2^E
  • (-1)^S表示符号位,当S=0,V为正数;当S=1,V表示负数
  • M表示有效数字,大于等于1,小于2
  • 2^E表示指数位

补充知识:一个十进制的浮点数据怎么表示成二进制形式 核心要点:整数部分除2取余,小数部分乘2取整 举一个简单的例子: 178.125

  • 整数部分除2取余,直至得到0。 178除2得89,余0 89 除2得44,余1 44 除2得22,余0 22 除2得11,余0 11 除2得5,余1 5 除2得2,余1 2 除2得1,余0 1 除2得0,余1 得到的余数从下往上排列得10110010,即为178的二进制表示
  • 小数部分乘2取整 0.125乘2得0.25,整0 0.25乘2得0.5,整0 0.5乘2得1.0,整1 得到的整数从上往下排列得001,即0.001为0.125的二进制表示
  • 合并上面的两点178.125的二进制表达方式为:10110010.011

举例 依旧沿用上面的178.125的例子。 178.125写成二进制的形式为:10110010.011,相当于1.0110010011*2^7; 按照上面的格式,S=0,M=1.0110010011,E=7

IEEE754规定:

  • 对于32位的单精度浮点数,最高位的1位是符号位S,接着的8位是指数位E,剩下的23位为有效数字M。
  • 对于64位的单精度浮点数,最高位的1位是符号位S,接着的11位是指数位E,剩下的52位为有效数字M。

IEEE754对有效数字M和直属E,还有一些特别的规定

  • 根据前面的介绍,我们了解到了M的范围为:1<=M<2,也就是说这个数的第一位总是1,因此可以舍去,只保留后面的小数部分的数字。
  • 至于指数E,情况比较复杂 首先,E是一个无符号的整数。这意味着,如果E为8位,它的取值范围为0到255;若果E为11位,它的取值范围为0到2047。但是,我们知道科学计数法中的E可以出现负数。所以IEEE754规定,存入内存时E的真实值必须加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。 然后,指数E在内存中的取出还可以再分成三种情况: 1、E不全为0或不全为1 这时,浮点数就采取下面的规则表示,即指数的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1. 2、E全为0 这时,浮点数的指数E等于1-127(或1-1023)即为真实值。有效数字M不再加上第一位的1,而是加上0。这样做是为了表示+-0,以及接近于0的很小的数字。 3、E全为1 这时,如果有效数字M全为0,表示正负无穷大(正负取决于符号位S)。

3、题目讲解

通过上面的介绍,你应该已经了解浮点型数据在内存中是怎样存储的了,那么开头的题目也就迎刃而解了。 首先,为什么整形数据9还原成单精度浮点数,就成了0.000000?

9->0000 0000 0000 0000 0000 0000 0000 1001 按照规定拆分,S=0,M=1-127,M=0.0000 0000 0000 0000 0001 001 也就是一个接近于0的数,所以输出0.000000

然后,为什么单精度浮点数9.0还原成整型数据,就成了1091567616?

9.0->1001.0->(-1)^0 * 1.001 * 2^3->S=0,M=1.001,E=3 那么,第一位的符号位S=0,有效数M等于001后面再加上20个0,指数E在内存中表示为3+127即1000 0010 最后写成二进制的表现形式为:0 1000 0010 001 0000 0000 0000 0000 0000 还原成十进制得1091567616