让我们定义任何函数句柄foo
:
foo = @(x) x*2
我正在尝试编写一个通用函数defFun
来生成函数foo
的{{3}},即 n 迭代调用foo
,在某种程度上它可以存储在另一个句柄函数boo
中,如下所示:
boo = defFun(foo,n)
例如,
foo = @(x) x^2;
boo = defFun(foo,3);
boo(3)
会提供6561 [== foo(foo(foo(3)))]
而boo(2)
会提供256 [== foo(foo(foo(2)))]
。
我尝试使用此代码编写defFun
但这些句柄处理起来很棘手。有什么想法吗?
function boo = defFun(foo,n)
h = foo;
for i=2:n
h = h(h);
end
boo = h
end
答案 0 :(得分:4)
我的代码非常类似于原始代码。我冒昧地重命名了一些变量。
对于单输入和单输出参数,您可以使用类似于您的代码的直接方法:
function ftoN = fIterate(f, N)
ftoN = f;
for i = 2:N
ftoN = @(x) f(ftoN(x));
end
end
这个将更快,它也适用于多个(但数量相同)的输入和输出。
function ftoN = fIterate(f, N)
ftoN = @(varargin) fIterateLocal(f, N, varargin{:});
function varargout = fIterateLocal(f, N, varargin)
varargout = varargin;
for i = 1:N
[varargout{1:nargin-2}] = f(varargout{:});
end
end
end
这两种方法都适用于此:
square = @(x) x^2;
square(2)
>> ans = 4
squaresquaresquare = fIterate(square, 3)
squaresquaresquare(3)
>> ans = 6561
直接方法将会相当缓慢,并受到MATLAB Maximum recursion limit
的限制。
timeit(@()feval(fIterate(@(X)X+1,400),0))
ans = 1.2160
间接方法将为您提供更多速度和灵活性:
timeit(@()feval(fIterate(@(X)X+1,400),0))
ans = 0.0072
答案 1 :(得分:3)
这里的3个解决方案依赖于构建字符串,然后使用str2func
来获取函数句柄。相同功能的不同实现,但结果的可读性不同。
请注意,在评论中突出显示( thanks knedlsepp ),递归n
的顺序不能超过32
。
一种方法是解析输入函数字符串定义并在将其转换为函数句柄之前在字符串中递归地重新创建它:
function boo = defFun(foo,n)
%% // retrieve the string of the initial function
A = functions(foo) ;
fstrfull = A.function ;
%% // find "input variables" in the header
[i1 i2] = regexp(fstrfull, '\(([^\)]+)\)' , 'once' ) ; %// probably can be improved, regexp are not my strong suit
strVar = fstrfull(i1+1:i2-1) ; %// => strVar='x' %// to get rid of the parenthesis returned by the regex
%% // isolate only the function expression (without the header)
ilast = strfind( fstrfull , ')' )+1 ; %// ilast= 5 find the last position of the header
fstr = fstrfull(ilast(1):end) ; %// fstr='x.^2' separate only function expression
%% // replace "variables" by the expression the desired number of time
strFinalFunction = fstr ;
for i=2:n
strFinalFunction = strrep(strFinalFunction, strVar, ['(' fstr ')'] ) ;
end
boo = str2func( ['@(' strVar ')' strFinalFunction ] ) ;
end
这会给你:
>> boo = defFun(foo,3)
boo =
@(x)((x.^2).^2).^2 // <= your function shows the full expression
>> boo(3)
ans =
6561
只要输入函数只输入一个变量作为输入,它就适用于更复杂的情况。
或者,有一种更简单的方法应该更通用。它不需要解析,因此可能在上述解决方案中的解析失败的情况下工作。缺点是功能定义变得非常不透明。
function boo = defFun2(foo,n)
cfoo = {foo} ; %// place the function handle in a cell
%// create a string calling the function on itself N number of times
strFun = ['@(x) ' repmat('cfoo{1}(',1,n) 'x' repmat(')',1,n) ] ;
%// Generate a function handle for the corresponding function
boo = str2func( strFun ) ;
但现在您的函数定义如下所示:
>> boo = defFun2(foo,3)
boo =
@(x)cfoo{1}(cfoo{1}(cfoo{1}(x))) // <= your function does not show what it does (only the number of time it calls itself)
可读性差得多,但它仍能提供正确的结果。
最后,如果可读性至关重要,您还可以在函数定义中包含原始函数的名称,但您必须求助于有争议的eval
。
function boo = defFun3(fh,n)
fname = inputname(1) ; %// get the name of the function which was called
eval( [ fname '={fh};' ] ) ; %// place the function handle in a cell
strFun = ['@(x) ' repmat([fname '{1}('],1,n) 'x' repmat(')',1,n) ] ; %// create a string calling the function on itself N number of times
boo = str2func( strFun ) ; %// Generate a function handle for the corresponding function
现在给你:
boo = defFun3(foo,3)
boo =
@(x)foo{1}(foo{1}(foo{1}(x))) // <= now you know that boo is the function 'foo' called on itself 3 times.
答案 2 :(得分:1)
如果函数句柄foo
仅包含数学公式(如示例中所示),则可以使用MATLAB Symbolic Toolbox计算boo
的公式
function boo = defFun(foo,n)
syms x; % Create a symbolic variable x
f = sym(foo); % Convert the function handle to a symbolic expression
g = symfun(f,x); % Create a symbolic function to work with
v = g;
for k=2:n % repeat n times
v = g(v);
end
boo = matlabFunction(v); % convert v to a function handle
end
在n=3
的示例中,这将创建函数句柄
foo = @(x) x.^2;
boo = defFun(foo,3)
boo =
@(x)x.^8
boo(3)
ans =
6561
答案 3 :(得分:0)
你只是让你的变量混淆了一下。您的问题是您将函数句柄输入到匿名函数而不是值。
这将以你的榜样为基础。
foo = @(x) x^2;
function boo = defFun(fcn_handle,n)
v = fcn_handle(n); % The output here is the value of the anonymous function
for i=2:n
v = fcn_handle(v);
end
boo = v;
end
defFun(foo,3)
ans = 6561