记忆功能是记住他们找到的值的功能。 如有必要,请在文档中心查看Mathematica中的相关背景。
假设您有以下定义
f[0] = f[1] = 1
f[x_] := f[x] = f[x - 1] + f[x - 2]
在你的一个软件包中。用户可以加载包并立即开始询问f [1000]。 这将触发$ RecursionLimit :: reclim错误消息并中止。 即使用户然后尝试更小的东西,比如f [20],到现在为止f的定义已经损坏并且结果不再好。当然,包开发人员可能会增加递归限制并警告用户,但我的问题是:
如何改进f定义,以便如果用户要求f [1000]他/她得到答案没有任何问题?我感兴趣的是一种捕获用户输入,分析它并采取评估f [1000]所需的任何步骤的方法。
我很容易想象,如果输入超过255(然后将其恢复到原始级别),可以更改递归限制,但我真正希望看到的是,如果有方法可以f找出它“知道”多少个值(fknownvalues)并接受任何输入< = fknownvalues + $ RecursionLimit没有问题,或者如果输入更高则增加$ RecursionLimit。
感谢您的帮助
答案 0 :(得分:8)
以下是代码,假设您可以根据输入参数的值确定$RecursionLimit
的值:
Clear[f];
Module[{ff},
ff[0] = ff[1] = 1;
ff[x_] := ff[x] = ff[x - 1] + ff[x - 2];
f[x_Integer] :=f[x] =
Block[{$RecursionLimit = x + 5},
ff[x]
]]
我正在使用本地函数ff
来完成主要工作,而f
只是使用Block
的{{1}}调用它包含$RecursionLimit
的正确值:
In[1552]:= f[1000]
Out[1552]= 7033036771142281582183525487718354977018126983635873274260490508715453711819693357974224
9494562611733487750449241765991088186363265450223647106012053374121273867339111198139373125
598767690091902245245323403501
修改强>
如果您希望更精确地设置$RecursionLimit
,可以将上面代码的一部分修改为:
f[x_Integer] :=
f[x] =
Block[{$RecursionLimit = x - Length[DownValues[ff]] + 10},
Print["Current $RecursionLimit: ", $RecursionLimit];
ff[x]]]
此处Print
声明仅供参考。值10
相当随意 - 要获得它的下限,必须计算必要的递归深度,并考虑已知结果的数量是Length[DownValues[ff]] - 2
(从{{1有2个一般定义)。这是一些用法:
ff
如果您还想限制可能的最大In[1567]:= f[500]//Short
During evaluation of In[1567]:= Current $RecursionLimit: 507
Out[1567]//Short= 22559151616193633087251269<<53>>83405015987052796968498626
In[1568]:= f[800]//Short
During evaluation of In[1568]:= Current $RecursionLimit: 308
Out[1568]//Short= 11210238130165701975392213<<116>>44406006693244742562963426
,这也很容易做到,沿着相同的路线。例如,在这里,我们将其限制为10000(再次,它在$RecursionLimit
内):
Module
例如:
f::tooLarge =
"The parameter value `1` is too large for single recursive step. \
Try building the result incrementally";
f[x_Integer] :=
With[{reclim = x - Length[DownValues[ff]] + 10},
(f[x] =
Block[{$RecursionLimit = reclim },
Print["Current $RecursionLimit: ", $RecursionLimit];
ff[x]]) /; reclim < 10000];
f[x_Integer] := "" /; Message[f::tooLarge, x]]
答案 1 :(得分:6)
对Leonid的代码略作修改。我想我应该将其作为评论发布,但缺少评论格式化使其无法实现。
自适应递归限制
Clear[f];
$RecursionLimit = 20;
Module[{ff},
ff[0] = ff[1] = 1;
ff[x_] :=
ff[x] = Block[{$RecursionLimit = $RecursionLimit + 2}, ff[x - 1] + ff[x - 2]];
f[x_Integer] := f[x] = ff[x]]
f[30]
(*
-> 1346269
*)
$RecursionLimit
(*
-> 20
*)
修改强>
尝试稀疏地设置$ RecursionLimit:
Clear[f];
$RecursionLimit = 20;
Module[{ff}, ff[0] = ff[1] = 1;
ff[x_] := ff[x] =
Block[{$RecursionLimit =
If[Length@Stack[] > $RecursionLimit - 5, $RecursionLimit + 5, $RecursionLimit]},
ff[x - 1] + ff[x - 2]];
f[x_Integer] := f[x] = ff[x]]
不确定它有多有用......