1+2=3,这是我们小时候就学过的一位数加减法。这道题非常简单,难度仅次于1+1=2.
什么?你觉得2-1=1更简单?啊这。
显然,按照常理来讲,0.1+0.2当然等于0.3
对于刚上小学二年级的小王来说事情没有那么简单。计算机课上,他用python编写了一个计算器,计算0.1+0.2的时候,却得到了0.30000000000000004这个离谱的答案。
![c1ad05fea4c8c8b453354c1bb8f6e788.png](https://i-blog.csdnimg.cn/blog_migrate/d549dc8a68c8c48904225fbf1831dd54.jpeg)
和小王一样,我们在小学二年级的高数课上就学过无穷小量的概念。这里0.3和0.30000000000000004只相差了一个很小的值,可以认为这是合理的误差。不过,如果遇到一些极端情况,这样的bug很有可能导致财务上的损失。举个例子,小王需要购买x只笔和y个本子送给二年级的同学们做高数题,他计算出需要支付的金额会超过实际需要的金额。若是他给全国乃至全世界的小学二年级的小朋友购买笔记本和笔,那么小王将额外产生一笔不必要的损失。
![1db3b5dc6eea48188dd0b24b7592fdc0.png](https://i-blog.csdnimg.cn/blog_migrate/0e32b23ca9157f46503e1cea53f6b473.jpeg)
那么python中为什么0.1+0.2不会得到0.3,反而得到0.30000000000000004呢?这要从二进制讲起。
我们今天所用的计算机,即便是显示10101010这样的二进制数字,还是显示233的十进制数字,他们在内存里都用010101的二进制表示。比如,8这个数字就用1000表示。最高位的1表示1*2的3次幂,其他三位表示为0*2的2、1、0次幂。所有加起来,一共是8.
但这个世界上不是只有整数,无理数和小数也是宇宙的一部分。计算机又怎样表示小数呢?
这里以0.1为例。取小数部分0.1,乘2,若小于1则用0表示,否则1表示,同时去掉整数部分。
0.1到0.2,0.4,0.8三次变换得到的都是0,但下一次1.6,1.2,0.4得到110.类似的,这样得到了000110来表示0.1 。实际上,计算机中的位数远远超过我所举例部分。
同样,0.2也被表示为001100 … …
![116ec3aef42b845040e10724c057f6b4.png](https://i-blog.csdnimg.cn/blog_migrate/b7db27d22cb3124299a3dbac15d78a15.jpeg)
不同于整数,不是每一个小数的小数部分的处理都能完全精确。0.125这样的数字乘3次即可得到1,而0.124和0.126则相对于更容易丢失精度。因此,二进制表示的小数是不一定精确的,存在误差是很正常的。
幸运的是,python,C#等语言都有针对财务方面的精准的小数运算。使用python的decimal库,可以得到想要的精度。
也许有小学一年级的小朋友会问,为什么计算机不做成十进制,反而要做成二进制的呢?
您可以关注“Daniel谈技术”,我们后面会对计算机历史和芯片进行科普。