qakcn
学生会会长
学生会会长
  • 注册日期2008-10-31
  • 最后登录2021-01-05
  • 生日1988-8-18
  • 光玉3394颗
阅读:1474回复:11

科普第11篇——14.52-14.49=0.0299999?

楼主#
更多 发布于:2011-05-05 19:47
今天在微博上看到了这样一条内容:
 [附件]

真奇怪呢,Google这么大个公司,编个计算器都会出错?

其实,事件的原因并不是Google的错,而是计算机的错!

究竟是怎么回事呢?

在《科普第3篇——2、8、10、16》里我们讲过,计算机表示数据都是用二进制的,因为这样更方便。

那篇里我们简单地讲了如何把其他进制的数转换为十进制,但只讲了整数,于是这里在补充一下小数吧。

一个数anan-1......a2a1a0.a-1a-2a-3......a-(m-1)a-m这个b进制的数(小数点在a0和a-1之间,m和n为正整数),其表示的数值就是:

anan-1......a2a1a0=an×bn+an-1×bn-1+......+a2×b2+a1×b1+a0×b0+a-1×b-1+a-2×b-2+a-3×b-3+......+a-(m-1)×b-(m-1)a-m×b-m
(b-m=1/bm,m为正整数)

例如,十进制3.14=3×100+1×10-1+4×10-2
二进制 110.011=1×22+1×21+0×20+0×2-1+1×2-2+1×2-3=4+2+0+0+0.25+0.125=6.375(十进制)
十六进制2C.BE=2×161+12×160+11×16-1+14×16-2=16+12+0.6875+0.0546875=28.7421875(十进制)

另外,还说过,十六进制、八进制与二进制之间也可以通过简单的对应关系转换,小数也不例外(对应关系表见《科普第6篇——字符编码》)。

二进制转换为十六进制(或八进制)是从小数点开始向左右分成四位(或三位)一节,不足的在整数部分最高位或小数部分最低位补0,每节都根据对应关系转换就行了。
如(1100101.01101)2=(0110 0101 . 0110 1000)2=(65.68)16

十六进制(或八进制)转换为二进制只要把各位对应的数写成四位(或三位)二进制数就行了。
如(A3.8C)16=(10100011.10001100)2

等等,讲的这些和文章一开始的内容有关吗?
目前看来是没关系,其实我只是想借这个机会把数制的内容再补充一下而已。接着看下去,你就知道文章一开始提到的问题的原因了。

接下来,是数制的转换,十六进制、八进制与二进制之间的转换前面已经说过了,下面说说从十进制转换吧。

原理说来很简单,从小数点左右开始,整数部分依次除以基数取余,从低位到高位,直到商为0;小数部分依次乘以基数取整,从高位到低位。

比如123.456,转换成二进制数:
整数部分:
123/2=61……1(低位)
61/2=30……1
30/2=15……0
15/2=7……1
7/2=3……1
3/2=1……1
1/2=0……1(高位)
即(123)10=(1111011)2

小数部分:
0.456×2=0.912……0(高位)
0.912×2=1.824……1
0.824×2=1.648……1
0.648×2=1.296……1
0.296×2=0.592……0
0.592×2=1.184……1
0.184×2=0.368……0
0.368×2=0.736……0
0.736×2=1.472……1
0.472×2=0.944……0
0.944×2=1.888……1
0.888×2=1.776……1
0.776×2=1.552……1
0.552×2=1.104……1
0.104×2=0.208……0
0.208×2=0.416……0(低位)

已经算了16位了,还没有结束,我们就暂且到此吧。

(0.456)10=(0.0111010010111100)2
所以(123.456)10=(1111011.0111010010111100)2


这下有没有点理解开头提到的问题的原因了呢?

没错,就是因为在数制转换中,小数是无法做到绝对精确转换的,在十进制下是有限小数的,在二进制下可能就是无限小数了。因为无法精确转换,所以计算的结果自然也有偏差了。

而且在计算机中,小数还不是直接转换来表示的,而是采用浮点数的方式来保存,浮点数是基于科学计数法的,也就是说123.456其实是表示为1.23456e2(1.2345×102)。

在《科普第9篇——为什么32位CPU不能支持大于4GB内存?》我们提到过,目前的32位处理器表示浮点数时,是1位符号位、8位指数位和23位尾数位的。
上面的尾数1.23456表示出来就是(1.0011110000001100000111)2
可见十进制的小数点移动了两位,小二进制数的小数点却不是简单地移动,这样又会造成一些误差(因为表示原来的小数部分的位数又少了一些)。

最终的结果就是,计算结果完全不是我们想像的那样!

当然,只要我们善加处理,在一定范围内的精确度还是可以保证的。所以,虽然出现这个结果本质上不是Google程序员出错造成的,但是对这种会出现误差的地方不加以认真对待就是程序员的不对了,至少你得保证在你的可显示的范围内是正确的。


==========之前的文章==========
科普第1篇——计算机色彩
科普第1篇补遗——CSS颜色
科普第2篇——光盘
科普第3篇——2、8、10、16
科普第4篇——电池
科普第5篇——浏览器
科普第6篇——字符编码
科普第7篇——加密解密
科普第8篇——移动通信技术
科普第9篇——为什么32位CPU不能支持大于4GB内存?
科普第10篇——智能手机简介

科普番外篇1——虽然没用但了解一下也很有趣的知识
喜欢0 评分0
mooncrazy
学生会会长
学生会会长
  • 注册日期2010-12-28
  • 最后登录2024-05-03
  • 生日1989-8-9
  • 光玉11146颗
沙发#
发布于:2011-05-05 19:57
那岂不是只要是小数运算就会出错了?
回复(0) 喜欢(0)     评分
mooncrazy
学生会会长
学生会会长
  • 注册日期2010-12-28
  • 最后登录2024-05-03
  • 生日1989-8-9
  • 光玉11146颗
2楼#
发布于:2011-05-05 20:11
回 1楼(mooncrazy) 的帖子
嗷原来是这样
回复(0) 喜欢(0)     评分
桜舞雪咒
学生会会长
学生会会长
  • 注册日期2009-05-01
  • 最后登录2021-10-30
  • 生日1991-3-23
  • 光玉11781颗
3楼#
发布于:2011-05-05 20:11
小旭上榜了……果然还是数制的原因啊
回复(0) 喜欢(0)     评分
颓废的王
光坂基金会
光坂基金会
  • 注册日期2011-03-03
  • 最后登录2014-07-18
  • 生日1988-11-11
  • 光玉1432颗
4楼#
发布于:2011-05-05 20:29
不是计算机专业的表示压力很大额!
我是一发子弹,子弹没有感情。
因此,没有迷惘,只会,飞向目标


回复(0) 喜欢(0)     评分
甜瓜包制作大师
学生会干部
学生会干部
  • 注册日期2009-11-29
  • 最后登录2021-10-09
  • 生日1994-1-6
  • 光玉3410颗
5楼#
发布于:2011-05-05 20:33
受教了,原来是浮点运算的问题
回复(0) 喜欢(0)     评分
琥珀
光坂硕士生
光坂硕士生
  • 注册日期2009-06-07
  • 最后登录2020-12-09
  • 生日1989-12-26
  • 光玉6903颗
6楼#
发布于:2011-05-05 21:53
嘛~~有时候也不一定都是数据转换的问题,

像数学上的拓扑学就有许多看似不相等,实际上确实相等的等式例如  1=0.9999999   什么的
回复(0) 喜欢(0)     评分
moku
光坂硕士生
光坂硕士生
  • 注册日期2010-03-11
  • 最后登录2021-11-17
  • 生日2014-7-21
  • 光玉5767颗
7楼#
发布于:2011-05-05 22:05
《Java 解惑》里看到过,应该用BigDecimal
回复(0) 喜欢(0)     评分
ct一剑
光坂博士生
光坂博士生
  • 注册日期2010-10-04
  • 最后登录2014-08-21
  • 生日1991-10-16
  • 光玉13939颗
8楼#
发布于:2011-05-05 22:07
没办法嘛,小数的二进制转换~~~不一定除的尽2
回复(0) 喜欢(0)     评分
脑袋の白琉璃
光坂大学生
光坂大学生
  • 注册日期2011-03-20
  • 最后登录2013-12-04
  • 生日1988-10-11
  • 光玉1424颗
9楼#
发布于:2011-05-06 03:01
科普系列最高.....
原来计算器的约算这么来的
用眼神杀死你……
回复(0) 喜欢(0)     评分
aitushu
光坂学士生
光坂学士生
  • 注册日期2009-08-14
  • 最后登录2013-04-08
  • 生日1950-1-1
  • 光玉3352颗
10楼#
发布于:2011-05-06 04:36
又学到好东西了
回复(0) 喜欢(0)     评分
saintxavier
光坂大学生
光坂大学生
  • 注册日期2010-10-17
  • 最后登录2019-11-13
  • 生日1989-9-14
  • 光玉1148颗
11楼#
发布于:2011-05-06 06:57
我觉得还是设计时的问题,这完全可以避免嘛~~
回复(0) 喜欢(0)     评分
游客

返回顶部