注意!这是所有编程语言共同的坑
The following article is from 麦叔编程 Author 小K
出品 | 麦叔编程 (ID:maishucode)
已获得原公众号的授权转载我们的电脑也叫计算机,但是这个计算机在计算小数(浮点数)运算的时候可能存在一个重大的Bug。
我们计算下1.2-0.1
,这个算式我们口算都能算出结果1.1
。
但是我用Python算了下,结果不是1.1
而是1.0999999999999999
。
如果不相信是这个结果,你可以自己尝试下下方的代码:
a = 1.2
b = 0.1
print(a-b)
有些小伙伴肯定会说,差这么一点点有啥关系嘛,无伤大雅的。
但是如果,刚好有个判断条件:
a = 1.2
b = 0.1
c = a - b
if c >= 1.1:
print(True)
else:
print(False)
输出结果:
False
从代码层面上看,毫无异议条件判断走的是True的分支,但是在debug的时候,却一直是False,这时身为开发的你,心态是否会爆炸呢?
造成的原因
人类在进行一些数值计算的时候,习惯性都会先转成十进制,而计算机则会转换成二进制再计算。
10除以3等于几?0.333333333...
无限循环的小数对吧,如果让我写出具体的值估计十辈子都写不完后面的333333....
正因如此,0.1
在转换成二进制的值时,对计算机来说这就是一个无限循环的数:
所以为了防止爆内存的事发生,计算机也像人类学习,四舍五入保留若干位小数。
❝计算机的保留逻辑是,舍0存1。
我所知的编程语言基本上都是这样的机制。
❞
解决方法
如果都照这个算法,那资本家不就算亏了么?
我往银行存我银行里假如有1.8亿的存款,我再往里存0.1亿,那我什么都没做就有1.9000000000000001亿了。
把亿单位转成个位数,
1900000000.0000001元,
白嫖0.0000001元。
资本家怎么会让我有白嫖的机会呢?所以引入了decimal
模块解决它:
import decimal
a1 = 1.8
b1 = 0.1
c1 = a1 + b1
print(c1)
a2 = decimal.Decimal("1.8")
b2 = decimal.Decimal("0.1")
c2 = a2+b2
print(c2)
输出结果:
1.9000000000000001
1.9
还有一种方法,就是把计算的结果以分数的形式展示出来。
❝以前上学的时候,同学问我,10除以3等于多少,我说3.333333...,然他说3.33333333... 乘以3等于几?我回答9.9999999999....
他就继续问我,为什么10/3 乘以 3 等于10?
❞
所以我就想,有些情况是不是用分数表示一个值的时候会更加准确呢?
在产生无限循环小数的除法运算中使用fractions
模块:
from fractions import Fraction
print(10/3)
print(Fraction(10,3))
输出结果:
3.3333333333333335
10/3
最后附上一个知乎上未解之谜
我把代码复写了下,供大家研究~
def add_digit(num):
if num < 1:
return 0
else:
n1 = num/10
small_point = n1 - int(n1)
# print(small_point)
n2 = small_point*10
print(n2)
return int(n2) + add_digit(n1)
print(add_digit(12))
<END>
程序员专属卫衣
商品直购链接
👇👇
【☝🏼点击查看更多详情】
推荐阅读: