与えられた言語で次のステートメントをどのように書くことができますか?
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)
Java
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
Mathematica:
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
回避できるのであれば、「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}
最後の2つの要素の差は10^-8未満です。したがって、8回の反復が必要です。
In[67]:= Length[%]
Out[67]= 9