数据的存储(浮点型篇)

目录

前言

一、例题引入

二、浮点数的存放规则

1.概念陈述

 2.通过案例分析

1)、转化为二进制

2)、存放的特殊规则 

3)、读取时E的特殊规则 

三、引例揭秘 

 四、浮点性存放精度丢失的问题


前言

在计算机语言中,除了整形,另外一大类型就是浮点型。它的存储方式和整形不尽相同,本文就仔细的带大家来了解浮点数存储的方法。


一、例题引入

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

 按照正常思路来讲,我们会认为第一个printf的输出值应该是9,第二个printf的输出值猜测为9.0;第三个printf的输出值猜测为9,第四个输出的值应当是9.0。(答案揭晓如下图)

 由结果可见,在输入类型和输出类型相同时,打印出来的结果毫无疑问是正确的。但是,对于第二个和第三个的打印值却出乎大家的预料,其中的原因就是浮点数在内存中的存放方法和整形完全不同

二、浮点数的存放规则

1.概念陈述

浮点型数据的存放的规则是根据国际标准IEEE(电气和电子工程协会) 754来定义的。任意一个二进制浮点数可以表示成下面的形式:

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

32位和64位数据的S、M、E的存放格式如下:

单精度

 双精度

 2.通过案例分析

以单精度浮点型进行举例,双精度浮点型可以自行类推。

1)、转化为二进制

例:-5.5 

       由于是负数,所以需要使得(-1)^S为负数。由此可以见得浮点数的符号位S的存储类似整形:1表示负数,0表示正数。

       然后计算有效数字位M,先把整数位转化为二进制,例子中的5就写成101,再把浮点数位转化为二进制,浮点数后每一位的权重是二分之一的n次方,0.5就是二分之一的一次放,所以浮点数的二进制就是1。将整形和浮点型合并,就得到了二进制形式的数字101.1。

       但是需要注意的是M的范围是大于等于一,小于二的。我们把101.1写成二进制的科学计数法:1.011*2^2,由此我们得到M为1.011,E为2。

2)、存放的特殊规则 

 根据国际标准IEEE,我们得到了-5.5的存储写法(-1)^S * M * 2^E=(-1)^1*1.011*2^2。此后,我们需要考虑的是有效数字M指数位E的存放规则有一些特殊的规则

有效数字M:由于M的范围是大于等于1,小于2。所以,一切的有效数字都可以表示为1.xxxxxx;其次,我们由上图可知,单精度浮点型给有效数字M分配的存储空间是23个二进制位,如果1.xxxxxx的1存储进去,就会占用一个二进制位,我们不妨可以将1省去,只把小数点后的xxxxxx存储进M,这样就用23个二进制位存进了一个24位的有效数字。在之后读取的时候只要再把1重新加上即可。此处理可以提高数据的精度(具体为何后文会提及)。

指数位E:首先,E是一个无符号整形,这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出

现负数的,所以就有规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。

知道了这些规则,我们就可以把-5.5的二进制数(-1)^1*1.011*2^2写入内存,写法就是把S E M按顺序拼接起来,所给位数没有填满的就用零补满

-5.5=(-1)^1*1.011*2^2=(S)1 (E)10000001 (M)011 0000 0000 0000 0000 0000

3)、读取时E的特殊规则 

E 不全为 0 或不全为 1
这时,浮点数就采用下面的规则表示,即指数 E 的计算值减去 127(或1023 ,得到真实值,再将有效数字M 加上第一位的 1
E 全为 0
这时,浮点数的指数 E 等于 1-127 (或者 1-1023 )即为真实值,由于2^(1-127)这样的数数字极其的小,有效数字M 不必再加上第一位的1 ,而是还原为 0.xxxxxx 的小数。这样做是为了表示 ±0 ,以及接近于0的很小的数字。
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; 
}

 本题中,n为整形,所以在内存中存储的数字为:

00000000 00000000 00000000 00001001

如果将他以单精度浮点型打印出来,第一个0为符号位(S)表示整数,符号位后面的八个0表示指数位(E),由于全是零,根据E读取的特殊规则,打印出来的结果就显示的时0.000000。

*pFloat为浮点形,所以在内存中存储的数字为:

(S)0 (E)10000010 (M)001 0000 0000 0000 0000 000000

将这个浮点型二进制存放数字用整形的形式表达出来就形成了一个很大的数字,用计算器算出结果可见和输出的结果是一致的

 四、浮点性存放精度丢失的问题

 由于浮点型在转化为二进制时,小数点后的十进制数字,要通过权重为二分之一的数字来拼凑实现,就会出现不能刚好凑出的情况。如下面的例子所示,结果只能无限逼近0.65,永远无法得到0.65本身,这就造成了浮点型精度丢失的问题,因此更多的有效位存放空间(M)可以提高精度。

例:5.65

0.65=1*1/2^1(0.5)+0*1/2^2(0,25)+1*1/2^3(0.125)+…………

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值