为什么print(0.3)会输出0.3而不是0.30000000000000004?

7
我认为我基本上理解了浮点数的工作原理以及为什么我们无法在某些操作中获得“精确”的结果。
我对这个SO问题感到困惑,其中@MikeMüller建议四舍五入。
我的理解如下。 如果我们写小数位,它看起来像这样:
1000 100 10 1 . 1/10 1/100 1/1000 在二进制中,它看起来像这样:
8 4 2 1 . 1/2 1/4 1/8 因此,我们可以在内存中精确地存储0.5、0.25或0.125,但不能精确地存储例如0.3。
那么Python为什么会输出以下内容呢?
print(0.1)
print(0.2)
print(0.3)
print(0.1 + 0.2)

>>>0.1
>>>0.2
>>>0.3
>>>0.30000000000000004

我认为应该输出。
>>>0.1
>>>0.2
>>>0.30000000000000004
>>>0.30000000000000004

我哪里错了?


我的问题不是浮点数计算有问题吗?的重复, 因为该帖子的提问者并不明白为什么0.1+0.2不等于0.3。这不是我问题的主题!


4
可能是Is floating point math broken?的重复问题。 - khelwood
为什么?1/10和2/10在二进制小数中无法准确表示。几乎所有现代计算机(截至2010年7月)都使用IEEE-754浮点算术,几乎所有平台都将Python浮点数映射到IEEE-754“双精度浮点数”。 754双精度浮点数具有53位精度,因此在输入时,计算机会努力将0.1转换为最接近的形式为J/2 ** N的分数,其中J是包含恰好53位的整数。重新编写https://docs.python.org/2/tutorial/floatingpoint.html#representation-error - Laser
3
它们不是重复的,关闭这个是一个错误! - peterh
@peterh 谢谢,我也这么认为... - JDurstberger
3个回答

12

因为它们不同,就像0.10.2已经没有正确的表示一样。所以:

>>>print("%.20f" % (0.1+0.2))
0.30000000000000004441

>>>print("%.20f" % 0.3)
0.29999999999999998890

>>>print(0.29999999999999998890)
0.3

所以对于Python打印输出,特别是考虑到纯粹的0.3表示比0.1 + 0.2更接近实际0.3,一切都取决于Python规则。

以下是来自Python文档的相关摘录:

有趣的是,有许多不同的十进制数共享最近似二进制分数。例如,数字0.10.100000000000000010.1000000000000000055511151231257827021181583404541015625都近似于3602879701896397 / 2 ** 55。由于所有这些十进制值共享相同的近似值,因此可以显示其中任何一个,同时仍保持不变性eval(repr(x)) == x

历史上,Python提示符和内置的repr()函数会选择具有17个有效数字的数字0.10000000000000001。从Python 3.1开始,Python(在大多数系统上)现在能够选择其中最短的并简单显示0.1


谢谢,我也想到了类似的方法。非常好的答案。 - JDurstberger

1

来自Python 3中浮点数的文档,

有趣的是,许多不同的十进制数都具有相同的最近似二进制分数。例如,数字0.1、0.10000000000000001和0.1000000000000000055511151231257827021181583404541015625都被3602879701896397 / 2 ** 55近似表示。由于所有这些十进制值共享相同的近似值,只要保留不变式eval(repr(x)) == x,就可以显示其中任何一个。

从历史上看,Python提示符和内置repr()函数会选择具有17个有效数字的数字0.10000000000000001。从Python 3.1开始,Python(在大多数系统上)现在能够选择其中最短的,只需显示0.1即可。

所以它显示0.3是因为这是存储为该二进制表示的最短字符串。稍高一点的结果0.1 + 0.2无法显示为比0.30000000000000004更短的字符串。

就像我在StackOverflow上找到了相同的位,永无止境的竞赛! - TNW

-1
为了让舍入问题不那么明显,通常会打印浮点数而不打印它们的最后一位数字,这是为了隐藏您希望看到的问题。
因此,0.30000000000000004将舍入为0.3。
但是,如果您故意进行避免此舍入的计算,就可以轻松地重现该问题。例如,将结果乘以1e + 6。然后你会看到,你所看到的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接