函数句柄内部的逻辑短路 [英] Logical short-circuit inside a function handle
问题描述
我有一个对任意大小的二维数组进行操作的函数句柄:
I have a function handle that operates on 2d arrays of arbitrary size:
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
DL1./DL2,[minLim maxLim])) ...
,DL1,DL2) - C1;
以下是其作用的自下而上细分:
Here's a bottom-up breakdown of what it does:
fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,[minLim maxLim])
- 该位在区间[minLim maxLim]
,其中fFitObj1
和fFitObj2
是之前可用的函数句柄,C1
是一些已知常量和DL1、DL2
.@(DL1,DL2)1/(fzero(...))
-fzero
的包装器,允许DL1
和DL2
由外部提供.arrayfun(@(DL1,DL2)...,DL1,DL2)
- 另一个包装器,它允许fzero
在DL1、DL2
以矩阵形式提供.R2T = @(DL1,DL2) arrayfun(...) - C1;
- 另一个允许从外部提供DL1, DL2
的包装器.立>
fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,[minLim maxLim])
- This bit looks for a zero of the considered function on the interval[minLim maxLim]
, wherefFitObj1
andfFitObj2
are function handles available from before,C1
is some known constant andDL1, DL2
are provided.@(DL1,DL2)1/(fzero(...))
- a wrapper forfzero
that allowsDL1
andDL2
to be provided from outside.arrayfun(@(DL1,DL2)...,DL1,DL2)
- another wrapper which allowsfzero
to correctly operate element-by-element whenDL1, DL2
are provided as a matrix.R2T = @(DL1,DL2) arrayfun(...) - C1;
- yet another wrapper that allows to provideDL1, DL2
from outside.
我的问题是有时矩阵 DL1, DL2
可能包含 NaN
值,在这种情况下 fzero
返回以下错误:>
My problem is that sometimes the matrices DL1, DL2
may contain NaN
values, in which case fzero
returns the following error:
Error using fzero (line 242)
Function values at interval endpoints must be finite and real.
这就是为什么我很自然地想到了可用的短路操作,所以我尝试将 any(isnan([DL1,DL2]))
合并到其中,这样 fzero
甚至不会被评估,如果它的输入是是 NaN
- 但无论我尝试什么(例如定制的三元运算符),fzero
似乎都会被评估并且代码错误.
This is why I naturally thought of the available operations with short-circuiting, so I tried to incorporate a any(isnan([DL1,DL2]))
into this so that fzero
won't even be evaluated if its inputs would be NaN
- but whatever I try (e.g. a custom-made ternary operator) the fzero
seems to be evaluated and the code errors.
期望的结果:我想实现对 fzero
的惰性求值,只在输入有效时发生(在本例中,不是 NaN
),否则返回 NaN
,如下面的编辑所示.
The desired result: I'd like to implement a lazy evaluation of the fzero
to only occur when the inputs are valid (in this case, not NaN
), and return NaN
otherwise as demonstrated in the Edit below.
相关资源:
这是一段说明问题的代码(MATLAB 2014a):
Here's a piece of code that illustrates the problem (MATLAB 2014a):
clear variables; clc;
LIM = [0 5];
fFitObj1 = @(x)x.^2; fFitObj2 = @(x)1;
C1 = 100;
[DL1A,DL2A,DL1B] = deal(ones(2));
DL1B(4) = NaN; DL2B = DL1B;
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-...
DL1./DL2,LIM)) ...
,DL1,DL2) - C1;
R2T(DL1A,DL2A) %//case A, runs fine
%{
// ans =
//
// -99 -99
// -99 -99
%}
R2T(DL1B,DL2B) %//case B, errors due to NaN
%{
// Error using fzero (line 242)
// Function values at interval endpoints must be finite and real.
//
// Error in @(DL1,DL2)1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM))
//
//
// Error in @(DL1,DL2)arrayfun(@(DL1,DL2)1/(fzero( .....
%}
想要的结果,如果 B 是:
The desired result, in case B is:
ans =
-99 -99
-99 NaN
推荐答案
在评论中提到:内联执行此操作是疯狂,最好使用单独的函数/.m
文件.
As already mentioned in the comments: Doing this inline is madness and you are much better off using a separate function / .m
file.
会的
- 更快
- 更容易阅读
- 更容易编写
- 更容易调试
例如,您可以以与此类似的方式执行此操作:
You could do this for example in a similar way to this:
function out = R2TComputation(DL1, DL2, minLim, maxLim, C1)
...%Compute whatever R2T would compute.
要获得与原始匿名函数相同的接口,您只需创建
To get the same interface as your original anonymous function has, you can simply create
R2T = @(DL1, DL2) R2TComputation(DL1, DL2, minLim, maxLim, C1)
这将在您创建此句柄时捕获 minLim
、maxLim
和 C1
的当前值 R2T
>.
which will capture the current values of minLim
, maxLim
and C1
at the time you create this handle R2T
.
另一种选择是使用 嵌套函数 而不是外部的.它可以访问父函数的变量,但仍然可以使用 if
、else
和您需要的所有其他基本工具.唯一的缺点:不能从其他文件中访问它.
Yet another option would be to use a nested function instead of the external one. It would have access to the parent function's variables, yet still be able to use if
, else
and all the other basic tools you need. Only downside: It is not meant to be accessed from within other files.
... % Main function stuff
function out = R2T(DL1, DL2)
if ...
out = ...
...
end
... % Use R2T ...
<小时>
然而,为了自由自在,这里是if-else
的内联版本,我本着Loren 的博文 和 我不建议使用,因为使用单个表达式代替相应的 if
-else
语句几乎没有任何好处.
However, for the sake of freedom of shooting oneself in the foot, here is an inline version of if-else
, which I wrote in the spirit of Loren's blog post and I do not recommend using, as there are hardly any benefits of using a single expression instead of the corresponding if
-else
statements.
ifelse = @(cond, varargin) varargin{1+~cond}(); %Only for the insane
如果你想让它做懒惰评估,你需要传递一个带有零参数的匿名函数,其中 ifelse
然后将评估(这就是 ifelse
中最后两个括号 ()
的用途):
If you want it to do lazy evaluation, you need to pass an anonymous function with zero parameters, which ifelse
will then evaluate (That's what the last two parentheses ()
in ifelse
are for):
ifelse(true, 42, @()disp('OMG! WTF! THIS IS CRAZY!!111'))
如果你只是简单地将 disp
的函数调用作为 ifelse
的参数而不使用 @()
,那么该函数将在我们之前被调用甚至可以访问 ifelse
.这是因为 MATLAB(与大多数其他语言一样)首先计算函数的返回值,然后将其作为参数传递给 ifelse
.
If you simply wrote the function call to disp
as an argument to ifelse
without @()
, the function would be called before we even access ifelse
. This is because MATLAB (as most other languages) first computes the return value of the function, which is then passed to ifelse
as a parameter.
在您的情况下,结果代码为:
In your case the resulting code would be:
R2T = @(DL1,DL2) arrayfun(@(DL1,DL2)...
ifelse(~any(isnan([DL1, DL2])), ...
@() 1/(fzero(@(x)fFitObj1(x)./fFitObj2(x)-DL1./DL2,LIM)), ...
NaN), ...
DL1, DL2) - C1;
这篇关于函数句柄内部的逻辑短路的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!