Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

>>> 0.4-0.3 结果为啥是 0.10000000000000003 #30

Closed
Cuick opened this issue Sep 10, 2019 · 4 comments
Closed

>>> 0.4-0.3 结果为啥是 0.10000000000000003 #30

Cuick opened this issue Sep 10, 2019 · 4 comments

Comments

@Cuick
Copy link

Cuick commented Sep 10, 2019

image

有没有大佬解释一下这是啥原因呢?

@Cuick Cuick changed the title print(-0.15 + 0.12 + 0.14 - 0.11) 打印结果1.38777878078e-17 >>> 0.4-0.3 结果为啥是 0.10000000000000003 Sep 10, 2019
@Cuick Cuick closed this as completed Sep 12, 2019
@Cuick
Copy link
Author

Cuick commented Sep 12, 2019

知道了

@roachsinai
Copy link

roachsinai commented Sep 12, 2019

虽然 @Cuick 已经找到了答案,写一下自己的理解:

[ins] In [14]: from decimal import *                                                                                                    

[ins] In [15]: getcontext().prec                                                                                                        
Out[15]: 28

[ins] In [16]: Decimal.from_float(0.3)                                                                                                  
Out[16]: Decimal('0.299999999999999988897769753748434595763683319091796875')

[ins] In [17]: Decimal.from_float(0.1 + 0.2)                                                                                            
Out[17]: Decimal('0.3000000000000000444089209850062616169452667236328125')


[ins] In [18]: 0.3                                                                                                                      
Out[18]: 0.3

[ins] In [19]: 0.1 + 0.2                                                                                                                
Out[19]: 0.30000000000000004

上面代码直接展示了0.1+0.20.3不是同一个东西,这不只是Python中的情况,可以说绝大多数编程语言的浮点数在这个问题上都是一致的。

  • [16]的输出是直接把0.3转换成二进制表示对应的十进制的值
  • [17]的输出是分别把0.10.2转换成二进制表示相加之后对应的十进制的值
  • [18]的输出对应[16]
  • [19]的输出对应[17],这个很直接二者都有0.30000000000000004

也就是说在Python解释器中直接输入0.3,其实际的二进制对应的值是0.3000000000000000444089209850062616169452667236328125,然后解释器print的时候肯定不是全部输出而是要round一下,那输出几位呢?原则就是**在没有引起混乱的情况下,输出的位数就尽量短`。

为什么这么说呢?

因为不是所有的浮点数都有二进制的精确表示,并且浮点数的二进制位数有限制,所以会存在多个浮点数对应一个二进制的情况(实际就是一个浮点数二进制对应了实数域的一个连续区间,该区间内的浮点数都会映射到这个二进制表示),比如:

[ins] In [23]: Decimal.from_float(0.30000000000000003) # 和0.1+0.2对应的一样,也就是输入和输出不一样                                                                                 
Out[23]: Decimal('0.3000000000000000444089209850062616169452667236328125')

上面那个不引起混乱的规则就是将输出的值反过来代入Decimal.from_float之后还必须是0.3000000000000000444089209850062616169452667236328125而不能是其他的值(还能映射回那个二进制)。而0.3000000000000000444089209850062616169452667236328125,不引起混乱的最短打印值(输出位数尽量短规则)就是round到0.30000000000000004位数再少就变成了0.3000000000000000也就是0.3,这个就换成二进制就是[16]的输出了。

ref

一个浮点数到底是怎么被转换为字符串输出?一个浮点数不精确,那么其输出的值是怎么被确定的呢? - 大宽宽的回答 - 知乎

@AsiaLi
Copy link

AsiaLi commented Jan 2, 2020

二进制表示浮点数会有截断误差 就是精度的问题 是正常的
问题是 如果我们想比较 0.1+0.2 之后的数值是否和0.3相等
也就是说从程序员的角度看 他们应该是相等的 输出是true
但是如果从计算机的角度看他们可能不等 那怎么解决呢?

@AsiaLi
Copy link

AsiaLi commented Jan 2, 2020

这个里面有个方法 只能比较很接近的情况下 认为相等https://stackoverflow.com/questions/5595425/what-is-the-best-way-to-compare-floats-for-almost-equality-in-python

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants