函数句柄内部的逻辑短路 [英] Logical short-circuit inside a function handle

查看:28
本文介绍了函数句柄内部的逻辑短路的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对任意大小的二维数组进行操作的函数句柄:

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],其中 fFitObj1fFitObj2 是之前可用的函数句柄,C1 是一些已知常量和DL1、DL2.
  • @(DL1,DL2)1/(fzero(...)) - fzero 的包装器,允许 DL1DL2 由外部提供.
  • arrayfun(@(DL1,DL2)...,DL1,DL2) - 另一个包装器,它允许 fzeroDL1、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], where fFitObj1 and fFitObj2 are function handles available from before, C1 is some known constant and DL1, DL2 are provided.
  • @(DL1,DL2)1/(fzero(...)) - a wrapper for fzero that allows DL1 and DL2 to be provided from outside.
  • arrayfun(@(DL1,DL2)...,DL1,DL2) - another wrapper which allows fzero to correctly operate element-by-element when DL1, DL2 are provided as a matrix.
  • R2T = @(DL1,DL2) arrayfun(...) - C1; - yet another wrapper that allows to provide DL1, 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)

这将在您创建此句柄时捕获 minLimmaxLimC1 的当前值 R2T>.

which will capture the current values of minLim, maxLim and C1 at the time you create this handle R2T.

另一种选择是使用 嵌套函数 而不是外部的.它可以访问父函数的变量,但仍然可以使用 ifelse 和您需要的所有其他基本工具.唯一的缺点:不能从其他文件中访问它.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆