2

我知道浮点数在大多数编程语言中并不是 100% 准确的,但我刚刚遇到了一个奇怪的问题。我还在学习 Python,所以制作了一个简单的程序,以尽可能少的硬币计算零钱。然而,当它达到 0.02 时,它似乎无法提供 2p 硬币,而是将其拆分为 2 个 1p 硬币。代码片段如下所示:

....
elif amountLeft / 0.02 >= 1:
    changeGiven.append("2p")
    amountLeft -= 0.02
else:
    changeGiven.append("1p")
    amountLeft -= 0.01

我已经在http://www.pythontutor.com0.02中查看过它,并且在最终迭代中显然amountLeft有任何可以减少到那个的东西。当我检查时,print 0.02 / 0.02 >= 1True按预期返回。

我在这里缺少什么明显的东西?

4

3 回答 3

6

好吧,既然您知道浮点数不是 100% 准确的,那么发现 0.02 不能完全表示为 Python 浮点数也就不足为奇了。它实际上存储为略高于 0.02 的值,如果您以非常高的精度打印该值,您可以看到:

>>> print '{0:.32f}'.format(0.02)
0.02000000000000000041633363423443

当您不断地从变量中减去 0.02 时,这个小错误就会累积起来。这是一个从 1.0 开始的示例,以显示我在说什么:

>>> x = 1.0
>>> for i in range(49):
...     x -= 0.02
...
>>> x
0.019999999999999383
>>> x / 0.02 >= 1
False

为避免此舍入错误,请使用十进制模块而不是浮点数:

>>> from decimal import Decimal
>>> x = Decimal('1.0')
>>> for i in range(49):
...     x -= Decimal('0.02')
...
>>> x
Decimal('0.02')
>>> x / Decimal('0.02') >= 1
True

或者,将所有值乘以 100,以便减去整数 2 而不是浮点 0.02,这也将避免舍入误差。

于 2013-05-29T16:00:17.500 回答
3

首先,与(假设不是负数)amountLeft / 0.02 >= 1大体相同,而且更简单一些。amountLeft >= 0.02amountLeft

使用整数算术(直接使用便士,会给你准确的结果,虽然你必须.在显示结果时手动添加:

from Decimal import decimal

amountLeft = round(amountLeft*100)

....
elif amountLeft >= 2:
    changeGiven.append("2p")
    amountLeft -= 2
else:
    changeGiven.append("1p")
    amountLeft -= 1

如果您确实需要一个程序以精确的方式处理小数,请使用 decimal 模块。假设输入是浮点数:

# Assume amountLeft contains a floating point number (e.g. 1.99)
# 2 is the number of decimals you need, the more, the slower. Should be 
# at most 15, which is the machine precision of Python floating point.

amountLeft = round(Decimal(amountLeft),2)  

....
# Quotes are important; else, you'll preserve the same errors 
# produced by the floating point representation.
elif amountLeft >= Decimal("0.02"):
    changeGiven.append("2p")
    amountLeft -= Decimal("0.02")
else:
    changeGiven.append("1p")
    amountLeft -= Decimal("0.01")
于 2013-05-29T16:07:50.700 回答
-4

欢迎来到浮点。0.02 / 0.02 不一定等于 1。我最好的建议是始终对所有内容使用整数运算。我整天都在做科学编程,但我还没有发现需要浮点的问题。为了清楚起见,让我重申一下:您认为可以用浮点运算解决的任何问题都可以用整数运算更有效地解决。我能想到的唯一例外是当您需要使用只接受浮点输入的库时。

如果您坚持使用浮点数,则需要使用舍入函数。

--------------------- 或 FJ 建议的十进制库。

于 2013-05-29T15:55:49.820 回答