这可能不是科学计算问题,而是更多 MATLAB 问题,如果是这种情况,请随时关闭或迁移问题。
求根问题在科学计算中经常遇到,形式多种多样;但在这种情况下,目标是使用算子分裂技术求解非线性时间相关 PDE。在不深入 PDE 问题的细节的情况下(因为它与我的主要问题无关),每个时间步都会执行以下几行:
S = arrayfun(@(x,y) fsolve(@(c)[x-c(1)-c(1)*c(2);y-c(1)*c(2)],rand(1,2),options),u,v, ...
'UniformOutput',false);
options 是设置 fsolve 参数的结构,u 和 v 是中等大小(~8k 或更大)的列向量,fsolve 返回一个向量(1 行 x 2 列),需要设置选项(用于 arrayfun)UniformOutput错误的。我可以用以下 for 循环替换这两行:
for i=1:length(u)
S(i,:) = fsolve(@(c)[u(i)-c(1)-c(1)*c(2);v(i)-c(1)*c(2)],rand(1,2),options);
end
这段摘录的运行速度是上一段的两倍。如果 S 提前初始化并转置(因此它与 MATLAB 的列优先顺序对齐),则时间差异会更加显着。显然,这种行为是意料之中的,因为 arrayfun 只是“隐藏”(内部化)了 for 循环,而且额外的函数句柄会引入额外的开销。
在这种观察下,函数arrayfun 的正确用例是什么?如果 for 循环更快,为什么有人会使用 arrayfun?特别是当(可以说)for循环更容易阅读时?
注意:有一些细微差别。例如,作为 arrayfun 的输出的 S 是一个元胞数组,与我们从 for 循环方法获得的 n×2 矩阵 S 形成对比。所以假设我不关心输出,它也可以在计算后被转储。我对为什么有人会在 for 循环中使用 arrayfun 的原因更感兴趣,因为 arrayfun 慢了 2 倍。
编辑 1:Octave 为 arrayfun 的存在提供了以下理由:“这对于不接受数组参数的函数很有用。”。但接着是“如果函数确实接受数组参数,最好直接调用函数。”,因为它们也只内化了 for 循环。在文档的最后,他们说内置的 @plus 函数比匿名函数快 60% @(x,y) x+y。这可能是因为@plus 的行为更像 C 宏,因此没有额外的函数调用开销。