您如何用给定的语言编写以下语句?
a(0) = 1
a_(n+1) = 1 - 1 / ( a_n + 3)
n
我需要找到when的最小值a_n -> 0.732050...
。
我在 Mathematica 中的尝试
a[(x+1)_] = 1 - 1/(a[x_] + 3)
问题显然出在这个a[(x+1)_]
. 但是,我不知道如何在 Mathematica 中进行迭代。
您如何用给定的语言编写以下语句?
a(0) = 1
a_(n+1) = 1 - 1 / ( a_n + 3)
n
我需要找到when的最小值a_n -> 0.732050...
。
我在 Mathematica 中的尝试
a[(x+1)_] = 1 - 1/(a[x_] + 3)
问题显然出在这个a[(x+1)_]
. 但是,我不知道如何在 Mathematica 中进行迭代。
a[0] = 1;
a[n_] := a[n] = 1 - 1/(a[n-1] + 3)
(注意记忆技巧。)
此外,a[n] 收敛(非常快)到 sqrt(3)-1:
Solve[x == 1 - 1/(x+3), x]
Python,最简单的:
def a(n):
if n == 0: return 1
return 1 - 1 / float(a(n-1) + 3)
# limit is sqrt(3) - 1
limit = 3.0 ** 0.5 - 1.0
# get 9 digits' precision
i = 0
while abs(a(i) - limit) > 1.0e-9:
i += 1
print i
这会发出8
,表明可能不需要进行递归消除或记忆等优化。
当然,通常我们希望通过数值而不是分析来获得限制,因此正常的循环方式会相当不同——最好封装在高阶函数中......:
# get a function's limit numerically
def limit(f, eps=1.0e-11):
previous_value = f(0)
next_value = f(1)
i = 2
while abs(next_value - previous_value) > eps:
previous_value = next_value
next_value = f(i)
i += 1
return next_value
非平凡的循环逻辑通常最好封装在生成器中:
def next_prev(f):
previous_value = f(0)
i = 1
while True:
next_value = f(i)
yield next_value, previous_value
i += 1
previous_value = next_value
在这个生成器的帮助下,limit
HOF 变得更加简单:
def limit(f, eps=1.0e-11):
for next_value, previous_value in next_prev(f):
if abs(next_value - previous_value) < eps:
return next_value
注意分离是多么有用:next_prev
体现了“获取函数的下一个和上一个值”的概念,limit
只是处理“循环何时终止”。
最后但并非最不重要的一点是,itertools通常为生成器提供了一个很好的替代方案,让您可以快速封装挑剔的迭代逻辑(尽管它确实需要一些时间来适应......;-):
import itertools
def next_prev(f):
values = itertools.imap(f, itertools.count())
prv, nxt = itertools.tee(values)
nxt.next()
return itertools.izip(prv, nxt)
爪哇
double A = 1;
int n = 0;
while (true) {
System.out.println(n + " " + A);
A = 1 - 1 / (A + 3);
n++;
}
Python
A = 1.0
n = 0
while 1:
print n, A
A = 1 - 1 / (A + 3)
n += 1
数学:
a[0] := 1
a[k_] := 1 - 1/(a[k - 1] + 3)
我替换了 k = n + 1,因为这使表达式更简单。结果是等价的。
Python
next = lambda x: 1.0 - (1.0 / (float(x) + 3.0))
last, z, count = -1, 0.0, 0
while last != z:
print count, z
last, z, count = z, next(z), count+1
如果可以避免的话,我会尽量避免写“while True”之类的东西。几乎可以肯定,我编写的任何代码都不会永远循环。在这种情况下,它为我运行了 16 次。16 比 ℵ-null 少很多。
Mathematica 中的一个单行,它给出了序列的确切元素的列表:
In[66]:= NestWhileList[1 - 1/(#1 + 3) &, 1,
RealExponent[Subtract[##]] > -8 &, 2]
Out[66]= {1, 3/4, 11/15, 41/56, 153/209, 571/780, 2131/2911, \
7953/10864, 29681/40545}
最后两个元素之间的差异小于 10^-8。因此,它进行了 8 次迭代:
In[67]:= Length[%]
Out[67]= 9