你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

浮点型的存储

2021/12/15 0:46:09

这篇文章纯属是为了加深对这个知识点的理解,大家看看就行,如有错误,欢迎指教。

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;

}

上面的程序运算的结果是:n的值是9

                                           *pFloat的值为0.000000

                                            num的值为:1091567616

                                            *pFloat的值为9.000000

大家可以不用先看懂这个程序,只需关注程序运行的结果。我想说明的是:以浮点型的形式存储并以整型的形式拿出与以整型的形式存储并用浮点型的形式拿出是不一样的,由此说明,浮点数和整数在内存中存储的方式是不同的。

num和*pFloat在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大?要理解这个结果,就要搞懂浮点数在计算机内部的表示方法。

详细解读:

        根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数v可以表示成下面的形式:                                                         (-1)^S *M *Z^E

其中 ,S表示符号位,M表示有效数字(1<=M<2),Z^E表示指数位

并且,当S=0时,v为正数

           当S=1时,v为负数

如:有一个十进制的浮点数5.5,我们先将它转化成二进制形式。

可能有些朋友不太熟练小数转换成二进制,这里我来演示一下:

科学记数法是一种记数的方法。把一个数表示成a与10n相乘的形式(1≤|a|<10,n为整数),这种记数法叫做科学记数法。

例如:51400000000=5.14×1011,计算机表达10的幂是一般是用E或e,也就是51400000000=5.14E11或5.14e11。

IEEE 754规定:对于32位的浮点数,最高位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。double是64位浮点数

 

 IEEE 754对有效数字M和指数E,还有一些特别的规定:前面说过,(1<=M<2),也就是说M可以写成1.xxxxxxxxx的形式,其中xxxxxxxxxxx表示小数部分。

IEEE 754规定:在计算机内部保存M时,默认这个数的第一位总是1,因此,可以被舍去,只保留后面xxxxxxxxxxx的部分。比如保存1.01的时候,只保存01,等读取的时候,再把第一位的1加上去,这样做的目的是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位去掉后,等于可以保存24位有效数字。

至于指数E,它的情况较为复杂:

  首先,E是一个无符号整数,这意味着,如果E为8位,它的取值范围为0~255(2^8)。如果E为11位,它的取值在0~2047之间。但是,我们知道,科学计数法中的指数可以是为负数的,所以IEEE 754规定,存入内存E的真实值必须再加上一个中间数,这个中间数是127,对于11位的E,这个中间数是1023.比如,2^10的E是10,所以保存32位浮点数时,必须存10+127=137,即10001001。

比如:浮点数:0.5

二进制:0.1 -> 1.0*2^(-1) 

其中 S=0  M=1.0 E=-1

在float中,E以-1+127=126 变成二进制的形式存入内存中。

在double中,E以-1+1023=1022 以二进制的形式存入内存中。

好,我们再来举个例子:

int main()

{

      float f=5.5f;

//二进制: 101.1

//  1.011*2^2

// S=0   M=1.011  E=2

// S=0   M=1.011  E=2+127=129

//存入内存中

//   0  10000001  01100000000000000000000

//   0100  0000  1011  0000  0000  0000  0000  0000  转化成16进制(4个二进制位表示一个16进制位)

//       4      0         b        0        0        0        0         0

//       40  b0  00  00

      return 0;

}

然后,指数E从内存中取出还可以分成三种情况:

1、E不全为0或不全为1

这时,浮点数就采用下面的规则来表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位1。

比如:0.5的二进制位是0.1,由于规定正数部分必须为1,即小数点右移移位,则为1.0*2^(-1),它的阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐到23位0000 0000 0000 0000 0000 000,则其二进制的表示形式为:

0  01111110 00000000000000000000000

2、E全为0

这时,浮点数的指数等于1-127(或者1-1023)即为真实值,有效数字M不在加上第一位的1,而是还原为0.xxxxxxxxxx的小数。这样做是为了表示±0,以及接近与0很小的数字。

3、E全为1

这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s)

 了解了这么,应该对浮点数在内存的存储有一定了解了吧。我们现在再来看这道题

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的二进制是:

00000000 00000000 00000000 00001001

*pFloat 取出来的是浮点数,那么我们认为存储在内存中的也是浮点数

0  00000000 00000000000000000001001

S       E                          M

0.00000000000000000001001*2^-126

所以第一个*pFloat的值是0.000000

现在*pFloat=9.0

9.0

1001.0

1.001*2^3

E=127+3=130

0  1000010  00100000000000000000000

感觉写的好烂,你们随便看看。