如何在 Python 3 中不设置范围的情况下执行 while 循环?
How to perform a while loop without setting a range in Python 3?
我发现了一个有趣的 Python 练习并尝试编写代码。我需要编写执行以下操作的代码(无需任何库或模块的帮助):
- 创建无限系列
1 - 1/3 + 1/5 - 1/7 + ...
- 执行计算:
4*(1 - 1/3 + 1/5 - 1/7 + ...)
- 进行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)
完成。
我发现了一个有趣的 Python 练习并尝试编写代码。我需要编写执行以下操作的代码(无需任何库或模块的帮助):
- 创建无限系列
1 - 1/3 + 1/5 - 1/7 + ...
- 执行计算:
4*(1 - 1/3 + 1/5 - 1/7 + ...)
- 进行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)
完成。