程序开发中的(小数)精度缺失问题--学习记录

刚开始做技术,接触的是硬件相关的编程,因此基本不用小数(浮点数)进行运算,也就没留意到计算机中小数“失精”存储的问题了。最近两年进行网络编程开发,也就是应用层开发了,工作上就接触到很多使用浮点数运算的场景,自然的,“失精”问题也就浮现了。

理清精确缺失问题(失精)

那么什么是”失精”问题?就是计算机是无法准确的存储大部分的十进制小数的。不信,可以运行以下C语言程序:

#include "stdio.h"
void main()
{
    printf("%.7f", 10.2f-9.0f);
    getchar();
}

结果输出:0.1999998 而不是0.2000000

既然知道了事实现象,我们就来研究下里面的真相。首先,我们将十进制的10.2用二进制表示:
1010.001100110011………无限小数 (不要问我怎么转的,自己回去补一下转换过程)

再者,将十进制9.0转化为二进制:1001(这个数小数部分为0,所以能够能用有限的数字表示)

好的,将两者相减,就得到:0.001100110011……… 因为计算机存储位数的限制,不可能存储无限位二进制数字,因此最终采用老办法– 截取高位存储,于是结果就是0.001100110011…(IEEE754标准存储24位有效数字),转换为十进制7位小数输出,就得到了0.1999998这个数字。

作为严谨的程序员,我们自然回想为什么十进制小数无法用二进制精确的表示呢?下面引入一个10cm长的杆子。
这里写图片描述
如果将1看做是这10cm的杆子,那么对于第一位小数,十进制的精度就是1cm,所以能准确的描述2/10的杆子长度4cm;但是二进制的精度是5cm,所以用二进制这个工具根本无法表示4cm,没法准确表示,怎么办呢?

那就无限逼近咯,于是就出现了课本上教我们的十进制转二进制的简易数学方法了。

好了,到此,就明白为什么0.2无法用二进制精确表示的了吧。

那么再总结下规律,十进制中的0.0-0.9这是个小数里面,出了0.0和0.5能被二进制准确表示外,其他都无法准确表示的。同理以2为基数的4进制8进制16进制都有和二进制相同的规律。

那么计算机程序是怎样处理这个问题的呢?

  1. 将浮点数用字符串存储起来,然后对字符进行十进制模拟运算,最后得出结果,这个方法在JAVA里面已经有现成的API。
  2. 对于比较成熟的语言,比如C,就会就运算之后,对结果进行进一步处理,如10.2-9.0=0.1999….,我们知道1位小数减去1位小数,得到的结果绝对不会超过1位小数。因此我们在运算前先记录最大的小数位数n,然后运算后,就对n+1位进行四舍五入的处理即可。

最后提醒一下,要注意一些不太成熟的语言如:php等脚本语言,例子如下

<?php
    $f = 0.57;
    echo (int)($f*100); //输出56而不是57
?>
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值