Python浮点数

10

我有点困惑,为什么 Python 在这种情况下会添加一些额外的小数数字,请帮忙解释一下。

>>> mylist = ["list item 1", 2, 3.14]
>>> print mylist ['list item 1', 2, 3.1400000000000001]

+1 是为了表扬你提出了一个聪明的问题,而不是假设这是 Python 的一个错误。 - Mark Rushakoff
1
类似于http://stackoverflow.com/questions/2880547/python-rounding-problem的问题。 - Mark Byers
这是一个常见问题解答:http://pyfaq.infogami.com/why-are-floating-point-calculations-so-inaccurate - dan04
4个回答

14

浮点数是一种近似值,不能精确存储小数。由于它们试图在只有64位的情况下表示非常大范围的数字,所以它们必须在某种程度上进行逼近。

非常重要的一点是要意识到这一点,因为它会导致一些奇怪的副作用。例如,您可能非常合理地认为十个0.1的总和应该是1.0。虽然这看起来很合乎逻辑,但在浮点数的情况下也是错误的:

>>> f = 0.0
>>> for _ in range (10):
...  f += 0.1
...
>>> print f == 1.0
False
>>> f
0.99999999999999989
>>> str(f)
1.0
你可能认为 n / m * m == n。然而,在浮点数世界中,这并不正确。
>>> (1.0 / 103.0) * 103.0
0.99999999999999989

或者同样奇怪的是,有人可能认为对于所有的nn + 1 != n。 在浮点数领域,数字并不像这样工作:

>>> 10.0**200
9.9999999999999997e+199
>>> 10.0**200 == 10.0**200 + 1
True
# How much do we have to add to 10.0**200 before its 
# floating point representation changes?
>>> 10.0**200 == 10.0**200 + 10.0**183
True
>>> 10.0**200 == 10.0**200 + 10.0**184
False

请参阅计算机科学家应该了解的浮点数知识,这是一个关于相关问题的绝佳概述。

如果您需要精确的十进制表示,请查看decimal模块,它是自2.4版本起成为Python标准库的一部分。它允许您指定有效数字的数量。缺点是,它比浮点数慢得多,因为浮点操作是由硬件实现的,而十进制操作纯粹是在软件中完成的。它也有自己的不准确性问题,但如果您需要精确表示十进制数(例如金融应用程序),那么它是理想的选择。

例如:

>>> 3.14
3.1400000000000001
>>> import decimal
>>> decimal.Decimal('3.14')
>>> print decimal.Decimal('3.14')
3.14
# change the precision:
>>> decimal.getcontext().prec = 6
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.142857')
>>> decimal.getcontext().prec = 28
>>> decimal.Decimal(1) / decimal.Decimal(7)
Decimal('0.1428571428571428571428571429')

from decimal import * 追踪(最内层的): 文件“<交互式输入>”,第1行,位置? 导入错误:没有名为decimal的模块
当我尝试导入decimal模块时出现错误,我应该从哪里获取它?这可能听起来很愚蠢,但我是Python新手。
- user359925
十进制数在Python 2.4及更高版本中可用。 - President James K. Polk
2
@zhack,我们是一个开发者社区,回答问题并不图任何利益。请不要说你的问题很愚蠢。 - Warty

6
值得注意的是,Python 3.1拥有全新的浮点数输出例程,按照预期的方式进行四舍五入(此功能也已被移植到Python 2.7)。
Python 3.1 (r31:73572, Aug 15 2009, 17:12:41) 
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a = [3.14]
>>> print(a)
[3.14]

Python 3.1的新特性文档中可以看到:

现在Python使用David Gay的算法来找到最短的浮点数表示,以避免一些困扰二进制浮点数的混淆。

这一点可以很容易地看出来,比如像1.1这样的数字在二进制浮点数中没有精确的等价物。由于没有精确的等价物,表达式float('1.1')会计算出最接近的可表示值,即十六进制下的0x1.199999999999ap+0或者十进制下的1.100000000000000088817841970012523233890533447265625。这个最接近的值被用于后续的浮点数计算。


0

如前所述,这一切都与浮点数是近似值有关。

如果您想要精确性,可以使用十进制数(它是一个精确的表示): http://docs.python.org/library/decimal.html

a = [1.5, 1.49999]
a
[1.5, 1.4999899999999999]

from decimal import Decimal
b = [1.5, Decimal('1.4999')]
b
[1.5, Decimal('1.4999')]

请记住,许多非金融应用程序不需要精确度。而像 sinlnsqrt 这样的函数在任何基数下都不返回精确答案。 - dan04

-1

我们可以通过这个命令来修复它:

>>> x = 1.2 - 1.0
>>> x
0.19999999999999996
>>> y = float(str(x))
>>> y
0.2

我添加了来自@mark的答案


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