LTE系统调试记录7:float&double在内存中的储存方式

转载地址:float在内存中的储存方式      float型数据在内存中的存储形式

C语言中,对于浮点类型的数据采用单精度类型(float)和双精度类型(double)来存储,float数据占用32bit, double数据占用


64bit,我们在声明一个变量float f= 2.25f的时候,是如何分配内存的呢?如果胡乱分配,那世界岂不是乱套了么,其实不论是


float还是double在存储方式上都是遵从IEEE的规范的,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53。


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

1.                   符号位(Sign) :0代表正,1代表为负

2.                   指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储

3.                   尾数部分(Mantissa):尾数部分


其中float的存储方式如下图所示:



 

而双精度的存储方式为:



  R32.24和R64.53的存储方式都是用科学计数法来存储数据的,比如8.25用十进制的科学计数法表示就为:8.25*10^0 ,而120.5


可以表示为:1.205*10^2 , 这些小学的知识就不用多说了吧。而我们傻蛋计算机根本不认识十进制的数据,他只认识0,1,所以在计算机存储中,首先要将上面的数更改为二进制的科学计数法表示,8.25用二进制表示可表示为1000.01,我靠,不会连这都

不会转换吧?那我估计要没辙了。120.5用二进制表示为:1110110.1用二进制的科学计数法表示1000.01可以表示为1.0001*2^3 ,


1110110.1可以表示为1.1101101*2^6 ,任何一个数都的科学计数法表示都为1.xxx* 2^n, 尾数部分就可以表示为xxxx,第一位都是1嘛,干嘛还要表示呀?可以将小数点前面的1省略,所以23bit的尾数部分,可以表示的精度却变成了 24bit,而对于指数部分,因为指数可正可负,8位的指数位能表示的指数范围就应该为:-127-128了,所以指数部分的存储采用移位存储,存储的数据为元数据+127,


下面就看看8.5和120.5在内存中真正的存储方式。

 首先看下8.5,用二进制的科学计数法表示为:1.0001*2^3

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


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


下面说下取值范围和精度:
取值范围看指数部分:
float是有符号型,其中,8位指数位,2^8=(-128—127),因此实际的范围是-2^128—2^127,约为-3.4E38—3.4E38


同理double范围约是-1.7E308—1.7E308,
精度是看尾数部分:
float尾数位23位,2^23=8.3E6,7位,所以不同的编译器规定不同,有些是7位,有些8位
double尾数52位,2^52=4.5E15,15位,所以double的有效位数是15位



*****************************************************我是分割线******************************************************************



一个float型实数在内存中占4个字节,即32个二进制bit,从低位到高位依次叫第0位到第31位。这32位可以分为3个部分:符号位(第31位),阶码(第30位到第23位共8位),尾数(最低23位)。
1、符号位。最高位也就是第31位表示这个实数是正数还是负数,为0表示正数或0,为1表示负数.
2、阶码。第30位到第23位这8个二进制位表示该实数转化为规格化的二进制实数后的指数与127(127即所谓偏移量)之和即所谓阶码.
规格化的二进制实数的指数只能在-127----+127之间,所以,一个float型数的最大值在+2^127即+3.4*10^38,最小值在-2^127即-3.4*10^38.
3、尾数。其他最低的23位即第22位到第0位表示该实数转化为规格化的二进制实数后小数点以后的其余各位即所谓尾数.
例如,将十进制178.125表示成机器内的32个字节的二进制形式.
 
第一步:将178.125表示成二进制数:(178.125)(十进制数)=(10110010.001)(二进制形式);
第二步:将二进制形式的浮点实数转化为规格化的形式:(小数点向左移动7个二进制位可以得到)
10110010.001=1.0110010001*2^7 因而产生了以下三项:
符号位:该数为正数,故第31位为0,占一个二进制位.
阶码:指数为7,故其阶码为127+7=134=(10000110)(二进制),占从第30到第23共8个二进制位.
尾数为小数点后的部分, 即0110010001.因为尾数共23个二进制位,在后面补13个0,即01100100010000000000000
所以,178.125在内存中的实际表示方式为:
0 10000110 01100100010000000000000
 
 
再如,将-0.15625表示成机器内的32个字节的形式.
第一步:将-0.15625表示成二进制形式: (-0.15625)(十进制数)=(-0.00101)(二进制形式);
第二步:将二进制形式的浮点数转化为规格化的形式:(小数点向右移动3个二进制位可以得到)
-0.00101=-1.01*2^(-3) 同样,产生了三项:
符号位:该数为负数,故第31位为1,占一个二进制位;
阶码:指数为-3,故其阶码为127+(-3)=124=01111100,占从第30到第23共8个二进制位;
尾数为小数点后的01,当然后面要补21个0;
所以,-0.15625在内存中的实际表示形式为:
1 01111100 01000000000000000000000
 
可以用以下的程序验证:

void printfFloatBit(float f)
{ 
 int i,j;
 unsigned int byte=0;
 char ch,*p;
 p=(char *)(&f);
 printf(" .7f: ",f);
 for(i=sizeof(float)-1;i>=0;i--)
 {
  ch=*(p+i);
  byte=ch;


  for(j=1;j <=8;j++)
  {
   if(byte>=128) printf("1");
   else printf("0");
   byte <<=1;
   byte&=255;
  }
 }
 printf("\n");
} 


void main()
{
 float f1=178.125; 
 float f2=-0.15625;
 float f3=1.0;
 system("cls");
 printfFloatBit(f1);
 printfFloatBit(f2);
 printfFloatBit(f3);
 system("pause");
}


基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip基于bert实现关系三元组抽取python源码+数据集+项目说明.zip 个人大四的毕业设计、课程设计、作业、经导师指导并认可通过的高分设计项目,评审平均分达96.5分。主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。 [资源说明] 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设或者课设、作业,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96.5分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),供学习参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值