学过编程语言的人都知道,所有的编程语言都会有浮点数这种数据类型(不同的编程语言可能叫法不一样,但暂且可以把它理解为日常生活中的小数)。进行浮点数运算的时候,有时会发现计算的结果与正确的结果并不一样,例如,将0.1累加100次的时候,得到的结果并不是刚好是10,而是会存在误差(我得到的结果是10.09999999999998,不同的编程语言会可能会得到不同的结果,但结果都会出现小数,而不是整数10)。为什么计算能力如此强大的电脑也会犯如此低级的错误呢?接下来让我们一起看看电脑是如何处理小数的吧。
首先,电脑是用二进制来表示小数的(例如0.0101),而不是我们常用的十进制(例如0.5093)。那二进制与十进制有什么区别呢?简单来说就是,二进制数就是每一位只能用0和1来表示的数(例如10.11),而十进制数是每一位只能用0~9这十个数来表示的数(例如19.58)(历史上也出现了许多其他的进制,有些现在还在使用,有兴趣的可以去了解相关的进制发明史,还是挺有趣的)。
二进制数与十进制数之间,通过对应的运算规则就可以进行相互转换。下面举个例子来说明一下二进制数转换成十进制数(括号后面的数表示这个括号里面的数是多少进制的):
(1011.0011)2 = (11.1875)10
我们先将二进制数每一位都拆出来,从最低位开始,然后一位一位地转换成十进制数,在分别计算的时候把其它位的数都当成0。(2^n表示2的n次方,n为任意数。另外,不知道n为0或负数是如何算出来的,可以看查阅相关的资料或者看我上一篇文章:重新认识数学中的指数)
0.0001 = 1 x 2^(-4) = 1 x 0.0625 = 0.0625
0.001 = 1 x 2^(-3) = 1 x 0.125 = 0.125
0.00 = 0 x 2^(-2) = 0 x 0.25 = 0
0.0 = 0 x 2^(-1) = 0 x 0.5 = 0
1 = 1 x 2^0 = 1 x 1 = 1
10 = 1 x 2^1 = 1 x 2 = 2
000 = 0 x 2^2 = 0 x 4 = 0
1000 = 1 x 2^3 = 1 x 8 = 8
然后将上面的结果全部加起来就等于 11.1875
从上面的计算过程中也可以看出,当二进制数是连续的时候,十进制数数是非连续的。更直观一点,就是二进制数(0.0000)2~(0.1111)2转换成十进制数时只能表示表示为(0.5)10、(0.25)10、(0.125)10、(0.0625)10这4个数的相加组合(每个数只能取0或1次)。这说明了十进制数中有些数是不能用二进制数表示的,例如0.1。或许你会认为,只要二进制数多取一些小数总可以得到吧,但事实是,无论取多少位小数最多也只能转换为近似值(你也可以自己试一下)。
所以,下次写程序要进行浮点数运算时,要特别注意这个问题。一个较好的解决办法是将它转换成整数,然后将得到结果再转换回浮点数。
好了,希望这篇文章能对你们有所帮助,感谢大家的观看。
参考资料:
矢泽久雄.程序是怎样跑起来的.北京:人民邮电出版社,2017