C语言中浮点数在内存中的存储格式

首先给出查阅资料的一些链接:

http://www.kuqin.com/language/20100606/85209.html 

http://www.cnblogs.com/jillzhang/archive/2007/06/24/793901.html

http://en.wikipedia.org/wiki/IEEE_754-1985

首先来看两个例子:

#include 
#include 
union stu
{
    int i;
    char c;
    float f;

}a;

int main()
{
    FILE *fp;
    fp=fopen("a.txt","w");


    fprintf(fp,"%d\n",sizeof(char));//1
    fprintf(fp,"%d\n",sizeof(short));//2
    fprintf(fp,"%d\n",sizeof(int));//4
    fprintf(fp,"%d\n",sizeof(long));//4
    fprintf(fp,"%d\n",sizeof(float));//4
    fprintf(fp,"%d\n",sizeof(double));//8

    a.i=97;//int 类型在内存中占4个字节,97的二进制表示为00000000 00000000 00000000 01100001
    fprintf(fp,"%d\n",a.i);
    fprintf(fp,"%c\n",a.c);
    fprintf(fp,"%.100f\n",a.f);//找到某一float类型数在内存中的存储为00000000 00000000 00000000 01100001
    fprintf(fp,"%.100f\n",pow(2,-126)*(pow(2,-17)+pow(2,-18)+pow(2,-23)));

    fclose(fp);
    return 0;
}

运行结果:a.txt中内容为

1
2
4
4
4
8
97
a
0.0000000000000000000000000000000000000000001359259510395072600000000000000000000000000000000000000000
0.0000000000000000000000000000000000000000001359259510395072600000000000000000000000000000000000000000

#include 
#include 
union stu
{
    int i;
    char c;
    float f;

}a;

int main()
{
    FILE *fp;
    fp=fopen("a.txt","w");


    fprintf(fp,"%d\n",sizeof(char));//1
    fprintf(fp,"%d\n",sizeof(short));//2
    fprintf(fp,"%d\n",sizeof(int));//4
    fprintf(fp,"%d\n",sizeof(long));//4
    fprintf(fp,"%d\n",sizeof(float));//4
    fprintf(fp,"%d\n",sizeof(double));//8

    a.f=97;//float 类型在内存中占4个字节,浮点数97在内存中的二进制表示为0 10000101 1000010 00000000 00000000
    fprintf(fp,"%d\n",a.i);//0 10000101 1000010 00000000 00000000=1120010240
    fprintf(fp,"%c\n",a.c);//00000000=null
    fprintf(fp,"%.100f\n",a.f);
    fprintf(fp,"%.100f\n",pow(2,-126)*(pow(2,-17)+pow(2,-18)+pow(2,-23)));

    fclose(fp);
    return 0;
}

运行结果:a.txt中内容为

1
2
4
4
4
8

1120010240


97.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0.0000000000000000000000000000000000000000001359259510395072600000000000000000000000000000000000000000

第一个程序的a.f为什么为0.0000000000000000000000000000000000000000001359259510395072600000000000000000000000000000000000000000?
第二个程序的a.c=空?,a.i=1120010240?

这里就涉及到float类型的数在内存中的存储格式问题。

无论是单精度还是双精度在存储中都分为三个部分:

  1. 符号位(Sign) : 0代表正,1代表为负
  2. 指数位(Exponent:用于存储科学计数法中的指数数据,并且采用移位存储
  3. 尾数部分(Mantissa):尾数部分

其中单精度float的存储方式:

C语言中浮点数在内存中的存储格式_第1张图片

而双精度double的存储方式为: 

C语言中浮点数在内存中的存储格式_第2张图片

   R32.24和R64.53的存储方式都是用科学计数法来存储数据的,比如8.25用十进制的科学计数法表示就为:8.25*clip_image0021,而120.5可以表示为:1.205*clip_image0022。而我们傻蛋计算机根本不认识十进制的数据,他只认识0,1,所以在计算机存储中,首先要将上面的数更改为二进制的科学计数法表示,8.5用二进制表示可表示为1000.1。118.5用二进制表示为:1110110.1,用二进制的科学计数法表示1000.1可以表示为1.0001*clip_image002[2],1110110.1可以表示为1.1101101*clip_image002[3],任何一个数都的科学计数法表示都为1.xxx*clip_image002[1],尾数部分就可以表示为xxxx,第一位都是1,可以将小数点前面的1省略,所以23bit的尾数部分,可以表示的精度却变成了24bit,道理就是在这里,那24bit能精确到小数点后几位呢,我们知道9的二进制表示为1001,所以4bit能精确十进制中的1位小数点,24bit就能使float能精确到小数点后6位,而对于指数部分,因为指数可正可负,8位的指数位能表示的指数范围就应该为:-127~128了,所以指数部分的存储采用移位存储,存储的数据为元数据+127。

 首先看下8.5用二进制的科学计数法表示为:1.0001*clip_image002[2]

按照上面的存储方式,符号位为:0,表示为正,指数位为:3+127=130 ,尾数部分为0001,8.5的存储方式如下图所示:

C语言中浮点数在内存中的存储格式_第3张图片

而单精度浮点数118.5的存储方式如下图所示:

C语言中浮点数在内存中的存储格式_第4张图片

 

那么如果给出内存中一段数据,并且告诉你是单精度存储的话,你如何知道该数据的十进制数值呢?其实就是对上面的反推过程,比如给出如下内存数据:0100001011101101000000000000,首先我们现将该数据分段,0 1000 0101 110 1101 0000 0000 0000 0000,在内存中的存储就为下图所示:

根据我们的计算方式,可以计算出,这样一组数据表示为:1.1101101*clip_image002[3]=118.5

C语言中浮点数在内存中的存储格式_第5张图片

C语言中浮点数在内存中的存储格式_第6张图片

你可能感兴趣的:(C语言)