【问题标题】:calculation of pi, getting different value than book计算 pi,得到与 book 不同的值
【发布时间】:2015-10-12 04:48:36
【问题描述】:

数学常数 π (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

【问题讨论】:

  • 正如我在上一个问题stackoverflow.com/questions/33069677/find-the-value-of-pi 中发布的那样,我看不到error=0.01 如何返回3.1611 ...,3.1611986129870506 两侧的2 个值分别是3.121594652591011 和3.12236366153074。两者都不是
  • 因为(正如@skyking 所写)在 x=pi/4 处评估的 arctan(x) 的 McLaurin 展开是交替和,因此收敛缓慢。您可以通过配对项将其转换为仅正数公式,但它仍会缓慢收敛。阅读任何其他更快收敛的总和。

标签: python series pi


【解决方案1】:

您使用的近似值在收敛方面非常差,也就是说,您必须循环很多次才能获得合理的值。您会看到差异将是 1/d,这就是准确性。您必须循环 5000 次才能获得四位数字 50k 次才能获得下一个数字,500k 次才能获得下一个数字,依此类推(这是数字的指数时间复杂度)。

这可能是您在此处看到差异的原因之一,您只是遇到了舍入误差相加的情况。由于您需要使用如此多的迭代,因此您永远不会接近您正在使用的浮点数的全部精度。差异的另一个来源是您的参考可能正在使用另一个退出条件,在您的条件下,您应该得到一个小于提供的错误(理想情况下),并且您已经得到它(3.146567747182955-pi 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

【讨论】:

    【解决方案2】:

    我猜你的函数和 approxPi 的停止规则是不同的。事实上,你的估计更好。如果您打印出当前的所有值,您将看到当 i 等于 50 时,您的函数会产生您想要的输出。但是,它超越了这个范围并产生了更好的近似值。

    【讨论】:

      【解决方案3】:

      因此,要获得您正在寻找的答案,那么提出的问题在描述退出条件的方式上是错误的。
      重新组织得到 Pi = 4*(1/1 + 1/3 + 1/5 + ...),得到 3.1611986129870506,误差为 0.01,然后查看后续项并在项

      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 &lt; error*4。因此,要获得原始代码的正确退出,只需将错误乘以 4,例如:

      >>> pi(0.04)
      3.1611986129870506
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-03
        • 2021-12-25
        • 1970-01-01
        • 2018-04-29
        • 2019-04-23
        • 1970-01-01
        • 1970-01-01
        • 2016-09-21
        相关资源
        最近更新 更多