数学常数π(pi)是一个无理数,其值约为3.1415928 ...π的精确值等于下面的无穷和:π= 4/1 - 4/3 + 4/5 - 4 / 7 + 4/9 - 4/11 + ...我们可以通过计算前几个项的总和来得到π的良好近似值。编写一个函数approxPi(),它将浮点值误差作为参数,并通过计算上述和,逐项计算得出误差内的常数π,直到当前总和与前一个总和之差的绝对值(与少一个条款)不大于错误。一旦函数发现差异小于错误,它应该返回新的总和。请注意,此函数不应使用数学模块中的任何函数或常量。您应该使用所描述的算法来逼近π,而不是使用Python中的内置值。
我已经完成了以下程序,但出于某种原因,我从书中获得了不同的价值。
def pi(error):
prev = 1
current = 4
i = 1
while abs(current - prev) > error:
d = 2.0* i +1
sign = (-1)**i
prev = current
current = current + sign * 4 / d
i = i +1
return current
output In [2]: pi(0.01)
Out[2]: 3.146567747182955
但我需要获得此值
>>> approxPi(0.01)
3.1611986129870506
>>> approxPi(0.0000001)
3.1415928535897395
答案 0 :(得分:3)
您使用的近似值在收敛时非常差,即您需要循环很多次才能获得合理的值。你看到差异将是1 / d,这就是准确性。您将需要循环5000次以获得4个数字50k次以获得下一个并获得500k以获得下一个等等(这是数字的指数时间复杂度)。
这可能是你在这里看到差异的原因之一,你只是得到了舍入错误加起来的情况。由于您需要使用那么多迭代,您将永远无法接近您正在使用的浮动的完整精度。另一个差异的来源是你的引用可能正在使用另一个退出条件,你的条件你应该得到一个小于提供的错误(理想情况下),你已经得到它(3.146567747182955-pi <0.01)。实际上,您的引用似乎正在使用条件abs(current-prev) > 4*error
。
你正在使用的公式是pi = 4arctan(1)并且使用arctan(x)的McLaurin扩展得到x的值,该值完全收敛。为了获得更好的性能,应该在该扩展中使用较低的x。例如,可以使用pi = 16arctan(1/5)-4arctan(1/239)(这给出了数字的线性时间复杂度):
def pi(error):
a = 1.0/5
b = 1.0/239
prev = 1
current = 0.0
i = 0
while abs(current - prev) > error:
d = 2.0* i +1
sign = (-1)**i
prev = current
current = current + sign * (16*a - 4*b)/d
a = a*1.0/(5*5)
b = b*1.0/(239*239)
i = i +1
return current
答案 1 :(得分:0)
我猜你的函数和approxPi的停止规则是不同的。事实上,您的估计更好。如果打印出当前的所有值,您将看到当我等于50时,您的函数会产生您想要的输出。但是,它超越了这一点并产生了更好的近似值。
答案 2 :(得分:0)
因此,要获得您正在寻找的答案,那么所提出的问题在如何描述退出条件方面是错误的 重新组织你得到Pi = 4 *(1/1 + 1/3 + 1/5 + ...),得到3.1611986129870506,误差为0.01,然后你查看后续术语并在术语&lt;错误:
from itertools import count, cycle #, izip for Py2
def approxPi(error):
p = 0
for sign, d in zip(cycle([1,-1]), count(1, 2)): # izip for Py2
n = sign / d
p += n
if abs(n) < error:
break
return 4*p
然后你得到正确答案:
>>> approxPi(0.01)
3.1611986129870506
>>> approxPi(0.0000001)
3.1415928535897395
使用您的代码(来自@PaulBoddington:Find the value of pi)
def pi(error):
prev = 0
current = 1
i = 1
while abs(current - prev) > error:
d = 2.0*i + 1
sign = (-1)**i
prev = current
current = current + sign / d
i += 1
return 4*current
注意:这不是当前总和与前一个总和之间的差异,因此问题是错误的,但它等于difference_between_sums < error*4
。因此,为了获得原始代码的正确退出,只需将误差乘以4,例如:
>>> pi(0.04)
3.1611986129870506