Python Decimal提供的结果不正确

时间:2017-09-06 11:39:59

标签: python python-2.7 floating-point precision

我遇到以下计算问题:

Decimal(3)*(Decimal(1)/Decimal(3))

而不是返回1.0,它返回0.999 ...

无论我增加Decimal模块的精度多少,情况仍然如此。

以下是完整代码:

from decimal import Decimal
from decimal import getcontext
getcontext().prec = 800
print Decimal(3)*(Decimal(1)/Decimal(3))

具有讽刺意味的是,使用“原生”float解决了这个问题:

print float(3)*(float(1)/float(3))

毋庸置疑,我在这里使用Decimal进行更复杂的计算,涉及大数的取幂。遇到这个问题之后,我设法将它最小化到上面的例子。

谢谢。

2 个答案:

答案 0 :(得分:4)

在我的评论中稍微扩展一下:

Python中的十进制数字实际上是您可能手写的数字。重要的是,它并不理解递归的概念,因此像1 / 3这样的无限重复分数只表示为0.333333333333..,直到精度为止。如果将此值乘以3,则会得到0.99999.. - 这是明智的行为,因为在0.33333333..被截断后1 / 3实际上已知道DecimalFractionIn [1]: from fractions import Fraction In [2]: Fraction(3) * Fraction(1, 3) Out[2]: Fraction(1, 1) In [3]: print(_) 1 经常因为四舍五入而失去精确度(事实上当你除以2或5以外的因子时)。如果能够进行除法是至关重要的,请使用float,它代表任何有理数,而不会因分子和分母而失去任何精度:

Decimal

分数会自动简化。

随着你的浮动,我认为这是一个幸运的问题,舍入错误已经取消了。请注意,除非您需要绝对精度,否则FractionIn [4]: "{:.2f}".format(Decimal(3) * (Decimal(1) / Decimal(3))) Out[4]: '1.00' 可能已经足够好了,在这种情况下我会推荐0.9999999(例如,这意味着你可以可靠地进行平等测试)。你总是可以围绕一个丑陋的数字,使它至少看起来更漂亮:

1

如果你正在做类似模拟的事情,那么DecimalFraction之间的差异通常会真正重要。

另一个选择是重新调整你的操作顺序,以便保证分子可被分母整除,如下所示 Anilkumar的回答。如果可能的话,这是一个很好的解决方案,但有时你可能无法做到这一点 - 例如你期望结果是分数的,或者你得到一些分数乘数一种黑盒子。此时,可以跟踪Fraction分子和分母......然后你就会意识到Decimal类的作用是什么,但麻烦少了。

请注意,In [2]: Fraction("3.141") Out[2]: Fraction(3141, 1000) 可以使用>>> Fraction(1, 2) ** 4 Fraction(1, 16) >>> Fraction(1, 2) ** 0.5 0.7071067811865476 来执行float可以执行的操作,但更重要的是。任何可表示的十进制数也是一个分数(尾数超过10的幂)。例如:

sympy

当然,这会导致一些性能下降 - 分数必须跟踪更多数据,进行更多计算,并且可能更抽象。

看一下你新提供的公式 - 要小心当你将一个有理数提高到一个非整数的幂时,结果可能不合理,所以你可能会在某个地方失去分数,例如:

In [1]: from sympy import *

In [2]: sqrt(Integer(1) / Integer(2))
Out[2]: sqrt(2)/2

虽然在评估公式的背景下,尝试以符号方式存储所有内容并不是很有意义。这让我们回到粗略index.html:18 GET http://0.0.0.0:35729/livereload.js?snipver=1 net::ERR_CONNECTION_REFUSED system.js:4 GET http://localhost:8000/src/main.ts 404 (Not Found) Error: (SystemJS) Error: XHR error (404 Not Found) loading http://localhost:8000/src/main.ts Error loading http://localhost:8000/src/main.ts 经常足够好的想法。如果你真的想要某种surd输出格式,你可以给{{1}}一个镜头:

{{1}}

这当然会减慢你的速度。

答案 1 :(得分:0)

我认为要改变禁忌症:

from decimal import Decimal
from decimal import getcontext
getcontext().prec = 800
print (Decimal(3)*Decimal(1))/Decimal(3)

对于我来说,对于一个

,输出为1