<2011 11 7> 编程中数据处理的问题(二)浮点数运算与精度误差

    浮点数的运算误差主要来源于两个方面,“转换误差”和“运算舍入”。

 
所谓“转换误差”,先看一段C程序:

     float a = 0.65f;

  float b = 0.6f;

  float c = a - b;

此时c=0.5吗?运行结果其实是0.0499999523,为什么?是我们输入十进制的0.65和0.6其实转换成二进制时为:

  (0.65)10 = (0.101001100110011001100110011001100110011......)2

  (0.6) 10 = (0.10011001100110011001100110011001100110011......)2 

省略号就是无穷尽。而实际的存储只能是取前几位,造成转换误差。实际上我们输入十进制整数是能无误差转换成二进制,而小数却不一定(进制转换方法不详述)。

        来看什么时候这个数字会无法表示呢?那么只有两种情形:

  1)幂数不够表示了:这种情况往往出现在数字太大了,超过幂数所能承受的范围,那么这个数字就无法表示了。如幂数最大只能是10,但是这个数字用科学计数法表示时,幂数一定会超过10,就没办法了。

  2)尾数不够表示了:这种情况往往出现在数字精度太长了,如1.3434343233332这样的数字,虽然很小,还不超过2,这种情况下幂数完全满足要求,但是尾数已经不能表示出来了这么长的精度。

       有意思的是,有时候有些不大的整数也有可能造成转换误差,比如:对一个单精度浮点数(4 Bytes)赋值“20014999”,由于这个数表示成浮点式二进制为(注意是按照浮点二进制转换,有别于整数二进制):
        0  10010111  0011000101100111100 1100 
        从左到右三组数字分别是符号、幂指数、尾数。实际上,该尾数不是精确的,实际要是尾数位数足够的话,应该是                               0011000101100111100 10111
        注意看这个尾数,实际的尾数10111被舍入成1100。这样就造成了误差,此时这个浮点数变量实际存储的是“20015000”。
        要是使用双精度的double(8 Byte)则可以精确表示,其二进制表示为:
        0 10000010111  0011000101100111100101110000000000000000000000000000  注意加亮的尾数的确保存了精度。
        按照上一篇博客的理解,20014999这个数正好处在 “浮点数表示精度间隔的中间”。单精度的float无法表示它。因为浮点数的精度不是平均分布的呢,和整数的均布不同,浮点数精度是“两头差,中间好”。
 
 

所谓“运算舍入”误差,这个十进制运算是一样的(代数运算对进制无偏向性)。1/3=0.3333333……  ,以及按照级数计算出得一些无理数如π=3.1415926549…… 。这种运算舍入误差在二进制中同样存在,因此带来精度问题。还有一些运算中的舍入误差跟特定的机器实现有关,比如可能出现在加减法中、乘法中(这在下一篇博文中会详细说明)。

总之浮点数至少最后一位是不精确的,甚至有些在一段运算过后可能产生较大的精度误差。

 

       浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。一般在科学计算中浮点数的精度能够满足,不行就用double或者更多Bytes的扩展浮点类型。但是有些使用要注意,比如比较判断时,开头c代码中,判断 c==0.5 就会得到 false,因此一般使用 abs(c-0.5)<=0.0001 。还有一些情况是金融货币领域,对数字要求精确,比如一个人存了15000000元,你不能说他存了14999999。这时候有一些其他的解决办法。比如 C#中提供了Decimal类型,VB中提供了Currency类型,这些都是用很大的资源开销来处理精度,并不适合做科学计算,但是适合需要很精确的场合。

转载于:https://www.cnblogs.com/andrew-wang/archive/2012/11/05/2755216.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值