Python Pi近似

时间:2015-02-24 15:20:53

标签: python pi

所以我必须用以下方式近似Pi:4 *(1-1 / 3 + 1 / 5-1 / 7 + 1/9 -...)。它也应该基于迭代次数。所以函数应该是这样的:

>>> piApprox(1)
4.0
>>> piApprox(10)
3.04183961893
>>> piApprox(300)
3.13825932952

但它的工作原理如下:

>>> piApprox(1)
4.0
>>> piApprox(10)
2.8571428571428577
>>> piApprox(300)
2.673322240709928

我做错了什么?这是代码:

def piApprox(num):
    pi=4.0
    k=1.0
    est=1.0
    while 1<num:
        k+=2
        est=est-(1/k)+1/(k+2)
        num=num-1

    return pi*est

5 个答案:

答案 0 :(得分:2)

这就是你的计算方法:

4*(1-1/3+1/5-1/5+1/7-1/7+1/9...)

您可以通过在循环结束时添加k += 2来修复它:

def piApprox(num):
    pi=4.0
    k=1.0
    est=1.0
    while 1<num:
        k+=2
        est=est-(1/k)+1/(k+2)
        num=num-1
        k+=2
    return pi*est

此外,您计算迭代次数的方式也是错误的,因为您当时正在添加两个元素。

这是一个更干净的版本,它返回您期望的10次和300次迭代的输出:

def approximate_pi(rank):
    value = 0
    for k in xrange(1, 2*rank+1, 2):
        sign = -(k % 4 - 2)
        value += float(sign) / k
    return 4 * value

这是相同的代码,但更紧凑:

def approximate_pi(rank):
    return 4 * sum(-float(k%4 - 2) / k for k in xrange(1, 2*rank+1, 2))

答案 1 :(得分:1)

重要编辑: 谁希望这种近似产生PI - 引自Wikipedia

  然而,它收敛得非常缓慢 - 在产生500,000个术语之后   只有五个正确的十进制数字π

原始回答: 这是一个教育的例子。您尝试使用快捷方式并尝试通过在同一次迭代中处理k的两个步骤来实现加数的“振荡”符号。但是,每次迭代只需将k调整一步。

通常,至少在数学中,使用(-1)**i实现振荡符号。所以,我选择这个是为了更具可读性:

def pi_approx(num_iterations):
    k = 3.0
    s = 1.0

    for i in range(num_iterations):
        s = s-((1/k) * (-1)**i)
        k += 2

    return 4 * s

正如您所看到的,我已经改变了您的方法,以提高可读性。您无需在while循环中检查num,也不需要特定的pi变量。你的est实际上是一个逐步增长的总和,所以为什么不调用它s(“sum”是Python中的内置关键字)。根据您的公式,最后将总和与4相乘。

测试:

>>> pi_approx(100)
3.1514934010709914

然而,收敛并不是特别好:

>>> pi_approx(100) - math.pi
0.009900747481198291

您的预期输出在某种程度上是不稳定的,因为您piApprox(300)(根据您的3.13825932952应该离PI太远了。你是怎么想出来的?这可能会受到累积数值误差的影响吗?

修改

对于在10次和300次迭代后函数应返回的内容,我不太相信这本书。事实上,在10个步骤之后,中间结果应该没有数值误差。在那里,你是否同时采取两个k步骤确实有所不同。所以这很可能是我的pi_approx(10)和书籍之间的差异。对于300次迭代,数值误差可能严重影响了本书的结果。如果这是一本旧书,并且他们已经在C中实现了他们的例子,可能使用单精度,那么结果的很大一部分可能是由于数值误差的累积(注意:这是你可能有多糟糕的一个主要例子)受数值误差的影响:小值和大值的重复,它不会变得更糟!)。

重要的是你已经查看了数学(PI的公式),并且你已经实现了一个近似于该公式的工作Python版本。这是本书的学习目标,所以继续解决下一个问题: - )。

答案 2 :(得分:0)

def piApprox(num):                                                              
  pi=4.0                                                                      
  k=3.0                                                                       
  est=1.0                                                                     
  while 1<num:                                                                
    est=est-(1/k)+1/(k+2)                                                   
    num=num-1                                                               
    k+=4                                                                    

  return pi*est

也适用于实际任务使用math.pi

答案 3 :(得分:0)

这是一个稍微简单的版本:

def pi_approx(num_terms):
    sign    = 1.                  # +1. or -1.
    pi_by_4 = 1.                  # first term
    for div in range(3, 2 * num_terms, 2):   # 3, 5, 7, ...
        sign     = -sign          # flip sign
        pi_by_4 += sign / div     # add next term
    return 4. * pi_by_4

给出了

>>> for n in [1, 10, 300, 1000, 3000]:
...     print(pi_approx(n))

4.0
3.0418396189294032
3.1382593295155914
3.140592653839794
3.1412593202657186

答案 4 :(得分:0)

尽管所有这些答案都是非常好的近似值,但是如果您使用的是Madhava-Leibniz系列,则比您应该得出的结果要大得多,根据该网站,“在第21个词条中,π正确近似为11位小数,即3.14159265359” :https://en.wikipedia.org/wiki/Approximations_of_%CF%80

因此,更精确的解决方案可能是对此进行任何更改:

import math

def estimate_pi(terms):
    ans = 0.0
    for k in range(terms):
        ans += (-1.0/3.0)**k/(2.0*k+1.0)
    return math.sqrt(12)*ans

print(estimate_pi(21))

输出:3.141592653595635