计算机误差之谜
问题的由来
对于这件事情的思考,开始工作上碰到一个问题。
具体问题如下(简化后):
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实现。
推荐阅读
- ACSL|ACSL 美国计算机科学联赛 2016-2017 R4 摩天大楼-Skyscraper 题解
- 历史上的今天|【历史上的今天】2 月 16 日(世界上第一个 BBS 诞生;中国计算机教育开端;IBM 机器人赢得智能竞赛)
- 修行之谜
- 计算机网络基础TCP\HTTP\HTTPS
- 计算机网络|计算机网络——DHCP协议详解
- android|android today上下卡片,【精品文档】关于计算机专业大学生安卓系统有关的外文文献翻译成品(基于Android(安卓)的考勤管理系统(中英文双语对照)
- 计算机与时间
- 中国农业大学计算机就业薪资,2020年工资出炉,这个行业倒数第一,不过这类大学专业有金矿可挖...
- 网络|简单聊聊压缩网络
- 计算机教学楼起名,给教学楼起名字(富有诗意教学楼名字)