计算机误差之谜

问题的由来

对于这件事情的思考,开始工作上碰到一个问题。
具体问题如下(简化后):

public static void main(String[] args) {
        double d0 = 0.2;
        double d1 = d0 + 0.01;
        System.out.println(d1);
}

本来以为一个很简单的问题。结果计算机却输出了:
0.21000000000000002
人家说,进步往往来源于例外。看来,这是我进步的一次机会,哈哈!。

问题的根源

先抛出答案:二进制数本身表达能力的局限性。
为什么会这样? 先来给你演示一下:
二进制如何表示十进制:


binary.png

如二进制的10.101 表示为十进制就是:

所以,十进制的0.1,用二进制来表示,只能用如下方式:![](http://latex.codecogs.com/png.latex?\inline&space;\frac{1}{16}+\frac{1}{32}+\frac{1}{256}+\frac{1}{512}+\frac{1}{1024}. . .)
你会发现 . . .之后会有无穷多的数。
所以在十进制数中很简单的0.1,在二进制数中就是不能精确表达。
其实这个情况也很好理解,毕竟计数系统是一种符号化语言。而只要是语言就有其缺陷。十进制也有不能精确表达的数,比如无理数,无限循环小数。再如自然语言也有其缺陷之处。中文“鲜”的含义在英文中就找不到一个完美的表达。

问题的处理办法

计数系统在表达小数方面都有其缺陷。但是对于整数,都是可以精确表达的。如果我们可以把小数用整数来表示,这个问题不就解决了吗?
如何用整数来表示小数?
当你试着用一对一的方式去表达的时候,你会发现这是行不通的。所以我们用两个整数来表达一个小数。如:



这样的话十进制的0.1,就可被我们用1和-1来表示了。
这个处理办法在java语言中用BigDecimal实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 网站乱码问题我们会经常碰到,大多见于非英文的中文字符或其他字符乱码,而且,这类问题常常是因为编码方式问题,主要原因...
    波段顶底阅读 3,076评论 1 9
  • 抱枕魔咒再次显现。昨天睡前想到好久没有抱着你送我的抱枕入睡了,也好久不曾梦到你了,再一次把希望寄托于小熊。 这次梦...
    禾必阅读 165评论 0 0
  • 文/一位喵先生 二十多岁,不只是适婚年龄,更是创就一番事业的最佳年龄段。 1 薇薇在五年前,一个人跑到香港读书去了...
    一位喵先生阅读 1,078评论 3 9
  • 闭包复习 闭包概念:封闭空间,包裹 闭包的作用:延长变量的声明周期保护内部的数据,代码更安全为我们提供一种间接访问...
    GodlinE阅读 168评论 0 0