计算机误差之谜

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

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实现。

    推荐阅读