我有一个程序用于使用Chudnovsky算法逼近pi,但是我的等式中的一个非常小的项保持舍入为零。
以下是算法:
import math
from decimal import *
getcontext().prec = 100
pi = Decimal(0.0)
C = Decimal(12/(math.sqrt(640320**3)))
k = 0
x = Decimal(0.0)
result = Decimal(0.0)
sign = 1
while k<10:
r = Decimal(math.factorial(6*k)/((math.factorial(k)**3)*math.factorial(3*k)))
s = Decimal((13591409+545140134*k)/((640320**3)**k))
x += Decimal(sign*r*s)
sign = sign*(-1)
k += 1
result = Decimal(C*x)
pi = Decimal(1/result)
print Decimal(pi)
如果没有“十进制”术语,方程式可能更清晰。
import math
pi = 0.0
C = 12/(math.sqrt(640320**3))
k = 0
x = 0.0
result = 0.0
sign = 1
while k<10:
r = math.factorial(6*k)/((math.factorial(k)**3)*math.factorial(3*k))
s = (13591409+545140134*k)/((640320**3)**k)
x += sign*r*s
sign = sign*(-1)
k += 1
result = C*x
pi = 1/result
print pi
问题在于“s”变量。对于k> 0,它总是变为零。例如在k = 1时,s应该等于大约2.1e-9,但它只是零。因为这个我的所有术语在第一个= 0之后。如何让python计算s的确切值而不是将其舍入为0?
答案 0 :(得分:3)
尝试:
s = Decimal((13591409+545140134*k)) / Decimal(((640320**3)**k))
你正在做的算法是原生python - 通过允许Decimal对象执行你的除法,你应该消除你的错误。
在计算r
时,您也可以这样做。
答案 1 :(得分:2)
几条评论。
如果您使用的是Python 2.x,/
将返回整数结果。如果你想要一个十进制结果,你首先将至少一边转换为十进制。
math.sqrt()
仅返回~16位精度。由于您的C值仅精确到16位,因此您的最终结果将精确到16位。
答案 2 :(得分:2)
如果您在Python 2.x中进行数学运算,那么您应该将这一行放在每个模块中:
from __future__ import division
这会改变除法运算符的含义,以便在需要时返回浮点数以给出(更接近)精确答案。 x / y
如果int
和x
都是y
,则int
的历史行为会返回__future__
,这通常会迫使答案向下舍入。< / p>
如果需要,返回一个浮点数通常被认为是一种更好的方法来处理像Python这样鼓励鸭子打字的语言中的除法,因为你可以担心你的数字的值而不是得到不同类型的不同行为。
在Python 3中,这实际上是默认的,但由于旧程序依赖于分区运算符的历史行为,因此感觉这种变化太过于向后 - 与Python 2不兼容。这就是您必须使用{{1}}导入明确启用它的原因。我建议总是在可能正在进行任何数学运算的任何模块中添加导入(或者只是任何模块,如果你可能会被打扰)。你几乎永远不会对它感到沮丧,但没有它,我必须追逐一些模糊不清的错误。
答案 3 :(得分:0)
我觉得's'的问题是所有术语都是整数,因此你在做整数数学。一个非常简单的解决方法是在分母中使用3.0
。计算中只需要一个浮点数就可以返回一个浮点数。