Python的十进制给出

问题描述:

我在与以下计算的问题不正确的结果:Python的十进制给出

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这里更复杂涉及大数幂运算。在碰到这个问题后,我设法将它最小化为上面的例子。

谢谢。

+4

十进制数字根本无法表示分母为3的分数。请查看“分数”模块以精确计算有理数。 –

+0

欢迎来到十进制数字和电脑的美妙世界。有一些全数字方法课程讲解如何在计算机中使用小数进行多次计算时将精度损失降至最低。 – LhasaDad

+0

@拉萨爸爸:就像我说的,我正在做一个更复杂的计算,我的问题中的例子只是最小化问题。实际的计算是'Decimal(x)*((1 + Decimal(y)/ Decimal(z))**(Decimal(w)/ 1000000) - 1)',目的是模拟实现的公式在不同的(非pythonic)平台上。鉴于此目的,我不允许(假定)优化此计算的准确性(或以其他方式对此进行更改)。 – goodvibration

我认为paranthesis改变:

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

输出为1对我来说上面一个

扩大一点上我的意见:

Python中的十进制数是字面上的那种你可能会用手写下数字。重要的是,它不理解递归的概念,所以像1/3这样的无限循环分数只是表示为0.333333333333..直到您的精确度。当它乘以3时,得到0.99999.. - 这是明智的行为,因为在截断后它实际上不知道0.33333333..1/3Decimal由于分割时的舍入(事实上,除以2或5以外的因子进行分割)时,经常会失去精度。如果能够做到分工是至关重要的,使用Fraction,它由分子和分母表示没有任何精度损失任何有理数:

In [1]: from fractions import Fraction 

In [2]: Fraction(3) * Fraction(1, 3) 
Out[2]: Fraction(1, 1) 

In [3]: print(_) 
1 

一小部分会自动简化本身。

随着你的浮动,我认为舍入错误已经取消自己只是运气的问题。请注意,floatDecimal可能会足够好,除非你需要绝对精度,在这种情况下,我会建议Fraction(这意味着你可以可靠地进行平等测试)。您可以随时圆一个丑陋的数量,使其至少看起来有点漂亮:

In [4]: "{:.2f}".format(Decimal(3) * (Decimal(1)/Decimal(3))) 
Out[4]: '1.00' 

如果你正在做的事情就像一个模拟,0.99999991之间的差别往往不会真正多大关系。

另一种选择是重新调整您的操作顺序,使分子被分母整除,如 Anilkumar的答案所示。如果可能的话,这是一个很好的解决方案,但很可能有些情况下你不能这样做 - 例如,你期望结果是分数的,或者你从某种黑盒子得到分数被乘数。此时,可以跟踪Decimal分子和分母..然后你意识到这就是Fraction类所做的,但是麻烦更少。

请注意,您可以使用Fraction作为Decimal可以做的任何事情,但更重要的是。任何可表示的十进制数也是一个分数(尾数超过10的幂数)。例如:

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通常足够好的想法。如果你真的想要某种清音的输出格式,你可以给sympy一个镜头:

In [1]: from sympy import * 

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

这当然会让你放慢脚步甚至更多。

+0

谢谢,我正在检查您的建议;完成后会更新。 – goodvibration

+1

就像我说的,我正在做一个更复杂的计算,而我的问题中的例子只是最小化问题。实际的计算是'Decimal(x)*((1 + Decimal(y)/ Decimal(z))**(Decimal(w)/ 1000000)-1)',目的是模拟一个公式不同的(非pythonic)平台。考虑到这个目的,我可能不会改变公式的顺序(或其他任何东西),所以重新排序的建议对我来说是不可能的。 – goodvibration

+0

谢谢。这个'Fraction'模块在某些情况下似乎有某种不准确的地方。例如,考虑'Fraction(9999999999999999999999999999999223)*(1)**(Fraction(10)/ Fraction(9))',它返回'9999999999999999455752309870428160'。当然,如果我认识到这里的指数是1,那么我可以轻松地解决这个特定的情况。但是,我无法开始寻找特殊情况,例如本例中的情况。任何想法如何解决这个问题? – goodvibration