浮点数精度丢失问题

原则:计算机内部所有的运算都是二进制运算,所以任意数据会首先被转化为二进制存储。
在将10进制数转化为2进制数的时候,按照:
整数除二取余,小数乘二取整
的原则进行转换。
但是,大多数情况下,小数部分不能全部被消除,如:
0.15x2 = 0.3
0.3x2 = 0.6
0.6x2 = 1.2
1.2x2 = 2.4
2.4x2 = 4.8
4.8x2 = 9.6
9.6x2 = 19.2
…尾数循环。
按照小数的换算规则,不难猜到,只有小数部分为以下数列的值可以完全将尾数消除:
s = k/2^n (n ∈(0,+∞),k ∈(0,+∞),k<2^n)
那么,如果小数部分不满足此规则,就不能被准确地转化为2进制存储,系统就会自动选择一个近似值进行存储,这样再进行运算的时候就可能产生略微偏差。
实际测试代码(c)如下:
环境为centos7,gcc编译器
在这里插入图片描述
在这里插入图片描述
这虽然是一个软件问题,但是是由于硬件寄存器的存储方式引起的误差,暂时属于无法修复的错误。
(以上介绍或许已经解释了你遇到的问题,但是关键还是应该是以下,如何面对这个问题)。
从测试结果不难看出,虽然有精度丢失问题,但是实际上的偏差都很小,都仅仅在最后一位才发生数据丢失。
一般对于这个问题的引用情况有:
1.将其作为比较
float x;

if (x == 0)
这种写法不可取,x可能不为0,所以要判断浮点数是否为一个数值,不能用这种==来判断,而要用区间的方式来选择。
上面提到,精度丢失发生在都仅仅发生在末位,则一般情况下,我们使用的有效数据精度不会到达六位。那么可以选择一个有效数据精度以外的数值来进行范围选择。
如:一般需要的有效精度是3个小数。
那么,判断一个浮点数是否是0就写成
if ( x>0.0001 && x < -0.0001)
2.获取其运算值
如上测试
35.5 - 35.4 = 0.099998
这个数据如果被放大十倍后强制转为整数,结果就是0,但是实际上应该想要的是1,这将会是一个很严重的bug(为什么会有放大N倍转整,这是一个很常见的协议格式,在许多设备中都有使用).
解决办法仍然是选择一个在有效精度以外的数值来取消这种精度丢失的影响。如:
(35.5 - 35.4) + 0.001 = 0.100998
这样再放大转整就能得到正确的值。
一般对于浮点数精度的处理就是这两种情况。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值