如何在 Python 3 中不设置范围的情况下执行 while 循环?

How to perform a while loop without setting a range in Python 3?

我发现了一个有趣的 Python 练习并尝试编写代码。我需要编写执行以下操作的代码(无需任何库或模块的帮助):

  1. 创建无限系列
     1 - 1/3 + 1/5 - 1/7 + ... 
  2. 执行计算:
     4*(1 - 1/3 + 1/5 - 1/7 + ...) 
  3. 进行N次迭代,直到第n次与第n-1次迭代之差的绝对值小于等于0.00000000005,然后return计算出的值。

我的代码如下:

def pi(n):
    a = [0]*n
    calc = [0]*n
    dif = 1
    while abs(dif) > 0.00000000005:
        for k in range(0,n):
            if k==0:
                a[k] = -((-1)**(k+1))*(1/(2*k+1))
                calc[k] = 4*sum(a)
            else:
                a[k] = -((-1)**(k+1))*(1/(2*k+1))
                calc[k] = 4*sum(a)
                dif = calc[k] - calc[k-1]
    return calc[k]

我可能不得不调用函数,因为 n 是一个非常大的数字,因为我不知道差异何时会 <= 0.00000000005。有没有办法在不设置范围的情况下执行它,或者我应该总是从 n 的巨大值开始?我仍然得不到任何结果,所以我不知道是否我的 n 不够高,我根本得不到结果,或者这只是内存问题。

认为 可以在您指定的公差范围内计算无限级数而根本不使用太多内存,但是根据您编写代码的方式,我不确定如果您有更多要求,我只是想念。不管怎样,这是我的尝试:

import numba as nb # optional speedup

@nb.njit # optional speedup
def pi(tol = 5e-11):
   sign = 1
   denom = 1
   diff = 4/denom
   calc = diff
   while diff > tol:
       sign *= -1
       denom += 2
       diff = 4/denom
       calc += sign*diff
   return calc

numba 行是可选的,只是为了使其在测试期间 运行 更快。我知道您不能使用库,代码可以在没有这些行的情况下工作。

据我了解,您实际上并不需要存储所有以前的值,只需将它们加起来直到当前值。此外,连续迭代的值之间的差异始终是最后一个值本身(在迭代 n 你只需将最后一个值添加到总和),因此检查最后一次迭代的绝对值是否足够小于阈值。最后,您真的不需要将自己限制在 N 的任何值,因为这是一个无限系列,这绝对不是生产代码。 (这就是为什么使用 While True 是合适的,尽管它不被认为是最佳实践)。所有这些结论都导致了以下修改后的代码:

def pi():
    result = 0  # holds the sum until the current iteration
    k = 0
    while True:
        a = 4 * (-((-1)**(k+1))*(1/(2*k+1)))
        result += a
        if abs(a) < 0.00000000005:
            return result

        k += 1

您可以尝试定义自己的 class 而不是范围。根据您关于如何在没有模块或库的情况下实现的问题。

class Range(object):
  def __init__(self, last, first=0):
    self.first = first
    self.last = last

  def advance(self):
    self.first +=1

  def __next__(self):
    if self.first == self.last:
      raise StopIteration
    else:
      answer = self.first
      self.advance()
      return answer

  def __iter__(self):
    return self

def pi(n):
  # when you use arrays they take up lot of space in ram, as the list increases
  sum_ = 0
  prev = 0
  present = 0
  diff = 0
  while abs(diff) <= 0.00000000005:
    try:
      range_obj = Range(n)
      k = next(range_obj) # getting the first value
      while k < n:
        if k==0:
          sum_ += -((-1)**(k+1))*(1/(2*k+1))
          prev = 4 * sum_
        else:
          sum_ += -((-1)**(k+1))*(1/(2*k+1))
          present = 4*sum_
          diff = present - prev
        print("k value", k)
        print(diff)
        k = next(range_obj)
    except StopIteration:
      pass
  if present:
    # where k>0
    return present
  else:
    # only one value k = 0 
    return prev


print("final", pi(10))

itertools 模块提供了许多类型和函数来处理无限级数。

from itertools import count, accumulate, cycle
from operator import truediv

def pi(tol):
    last = 0
    for current in accumulate(map(truediv, cycle([4, -4]), count(1, 2))):
        if abs(current - last) < tol:
            return last
        last = current

你从一系列分数开始,这些分数的分子在 1 和 -1 之间交替(如果你立即乘以 4,则为 4 和 -4),分母是自然奇数。

4/1, -4/3, 4/5, -4/7, ...

pi 的近似值是级数的部分和。

4/1 = 4
4/1 - 4/3 = 2.666666...
4/1 - 4/3 + 4/5 = 3.46666...
4/1 - 4/3 + 4/5 - 4/7 = 2.8952380...

这个系列是known to converge slowly。在我的机器上,我看到以下增加 运行 次:

pi(0.0000005)  # ~2 seconds
pi(0.00000005)  # ~7 seconds
pi(0.000000005)  # ~60 seconds
pi(0.0000000005) # ~660 seconds
pi(0.00000000005)  # ???, estimated 100 minutes

按照这个速度,我不会屏住呼吸等待 pi(0.00000000005) 完成。