功能手柄内部发生逻辑短路 [英] Logical short-circuit inside a function handle
问题描述
我有一个可以处理任意大小的2d数组的函数句柄:
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)
-另一个包装器,当DL1, DL2
作为矩阵提供时,该包装器允许fzero
正确地逐个元素操作. -
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]))
合并到其中,这样即使输入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
推荐答案
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)
,它将在创建此句柄R2T
时捕获minLim
,maxLim
和C1
的当前值.
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
的嵌入式版本,我本着
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
如果您希望它执行惰性评估,则需要
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屋!