浮点数 存储

from: http://blog.csdn.net/dreamXren/archive/2005/11/25/536902.aspx

 

 

 

关键字: 体系结构 IEEE754 浮点数 存储

main()
{
  float f=123.456;
  printf("f=%f/n",f);
}
如果不运行上面的代码,让我们来直接判断,输出的结果会是什么?

 

而在你运行程序之后,结果却很让人诧异:123.456001。为什么会是123.456001?有六位小数可以理解,最后那个1是为何?有很多人解释说最后那个1是乱码,随机的。嘿嘿~~其实无论你运行它多少次,最后始终都跟着一个1。这最后的那个1不是乱码,更不是随机的。

 

在数学中,表示一个浮点数需要三要素:尾数(Mantissa)、指数(Exponent,又称为阶码)和基数(Base)。任意一个浮点数N可以表示成下列形式:N = M × BE,例如N(10) =1.234×10-6, N(2)= -0.001011×2011等。

 

M和E决定了浮点数的精度(precision),E指明小数点在B进制数据中的位置,因而E和B决定了浮点数的表示范围(range),浮点数的符号(Sign)是单独考虑,表示为:

 

    符号位(S)

 

 

 

 

 

 

 

 

阶码(E)

 

 

 

 

 

 

 

 

尾数(M)

 

 

 

 

 

 

 

 

为便于软件的移植,浮点数的表示格式应该有统一标准。1985年IEEE(Institute of Electrical and Electronics Engineers)提出了IEEE754标准。该标准规定基数为2,阶码E用移码表示,尾数M用原码表示,根据原码的规格化方法,最高数字位总是1,该标准将这个1缺省存储,使得尾数的表示精度多了一位。实数的IEEE754标准的浮点数格式为:

 

                        存储位数                    总位数             offset

              数符S     阶码E   尾数M                                                      

float)       1          8          23                32                127

double)   1          11         52               64                 1023


 

说明:

   1) 约定小数点左边隐含有一位1,实际上使尾数的有效位数为24位,即尾数为1.M

 

   2) 偏移值 = 2 ^ (尾数位数   阶码-1) – 1。必须从指数中减去偏移值,才能确定有符号指数的实际值。(?)

 

   3) 讨论float型:

      E = 0, M = 0 , 若 S = 0, 则N = 0;  S = 1, 则 N = -0。-0可以表示一个很小的数,小到在单精度格式中不能用数字和指数来表示。尽管如此,它们然小于0。

      E = 0, M ≠ 0, 则数是有效的,但不是规格化数, N =  (-1) ^ S × 2 ^ ( - 127) × (0.M)

      E = 255, M = 0, 则数为正或负无穷大, 这取决于S.     

      E = 255, M ≠ 0, 则N不是一个数,  表示为NaN.

      E = 1 ~ 254,  则N = (-1) ^ S × 2 ^ (E - 127) × (1.M), 为规格化数.

   4) 具体可以参见<编码的奥秘>一书。

 

 回到前面的问题,语句float f=123.456f; 经编译后生成的汇编语句为:

 

00401028   mov         dword ptr [ebp-4],42F6E979h

 

 十六进制值42F6E979h由何而来?

 

N (10) = 123.456,

 

换算成二进制表示:

 

N (2) = 1111011. 01110100101111001

= 1. 11101101110100101111001(...) * 2^6

 

   那么E – 127 = 6;  E = 127 + 6 = 133(10) = 10000101(2)

 

M = 111 0110 1110 1001 0111 1001 (省略了最高数字位1, 共23bit)

 

   组合起来就是:

 

S          E                        M

 

0        10000101      111 0110 1110 1001 0111 1001

 

 4bit一间隔:

 

0100   0010   1111   0110   1110   1001   0111   1001

 

 4       2       F      6      E      9       7      9

 

 

再由42F6E979h还原为float型

 

取出十六进制数42F6E979h, 化为二进制为
0*100 0010 1*111 0110 1110 1001 0111 1001(*为区分点)
s=0, E=133, M=(1/2+1/4+1/8+1/32+1/64+1/256+1/512+...)=0.92900002002716064453125

N=1*64*(1+0.92900002002716064453125)=123.45600128173828125

哈哈...
大功告成,与输出的结果吻合.

 

如果真要结果的话,可以这样:
printf("f=%0.3f/n",f);

以上环境为Window XP Professional + SP2,  Intel P4,  VC6.0


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/dreamXren/archive/2005/11/25/536902.aspx

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值