2012-03-04 24 views
3

假设我有一个函数可以计算一个输入的一个输出,向量化涉及while循环或if循环中的if子句的函数(Matlab)

function y = sqrt_newton(x) 
    y = x ./ 2; 
    yo = y; 
    y = 0.5.*(y + x ./ y); 
    while abs(y - yo) > eps * abs(y) 
     yo = y; 
     y = 0.5.*(y + x ./ y); 
    end 
end 

我希望能够给这个函数应用到向量输入说sqrt_newton(2:9)像内置的功能。在循环开始时的条件或一些if-子句内部的条件下达到此目的的最佳方法是什么?如果可能的话,我想避免编写一个额外的函数作为包装器来循环输入向量。

我现在麻烦的解决方案

我做的到现在为止是:

  • 我必须展开第一输入相同的尺寸(使用finargsz从金融工具箱,但如果你知道另一个核心功能是一样的,那会很棒)

  • 使用size来记录形状

  • deal输入

  • 环通的所有投入要素

  • reshape输出

看来,numel功能减轻所有这一切繁重的工作需要,但额外的意见将非常欢迎。

回答

2

总是有arrayfun。你可以保留你的代码,把它放到一个内部函数中。

function y = sqrt_newton(z) 

    y = arrayfun(@inner, z); 

    function y= inner(x) 
     y = x ./ 2; 
     yo = y; 
     y = 0.5.*(y + x ./ y); 
     while abs(y - yo) > eps * abs(y) 
      yo = y; 
      y = 0.5.*(y + x ./ y); 
     end 
    end 
end 

编辑:上述方案具有容易实现你拥有了它与一个1x1的输入工作后的优势,但在其他的答案中环是大投入的方式更快。例如,我的电脑,代码

tic; sqrt_newton(rand(500)); toc 

运行在~1.24 seconds我的代码,0.06 seconds与@ Ramashalanka的代码,并与0.28 seconds @ GuntherStruyf的代码上。

+0

好吧,我喜欢你的解决方案,因为它相对于原始函数具有最小的开销。太糟糕了,它太呆滞了。 – 2012-03-05 01:03:41

2

我认为一般情况下,你必须使用一个循环,因为函数操作的未知字符。如果是线性操作,矢量化是可能的。

对于您的例子我会使用下列内容:

function y = sqrt_newton(x) 
    y = x ./ 2; 
    yo = y; 
    y = 0.5.*(y + x ./ y); 
    for i=1:numel(x) 
     while abs(y(i) - yo(i)) > eps * abs(y(i)) 
      yo(i) = y(i); 
      y(i) = 0.5*(y(i) + x(i)/y(i)); 
     end 
    end 
end 

我用numel,而不是大小,因此它可以处理任何阵列我扔在

+0

事实上,我使用了类似的解决方案,但我期待着其他方式来整齐地做到这一点。在这个问题下看到我的额外评论。 – 2012-03-05 01:12:06

2

嗯,你能矢量化它如下(any):

function y = sqrt_newton(x) 
    y = x/2; 
    yo = y; 
    y = 0.5*(y + x ./ y); 
    while any(abs(y - yo) > eps * abs(y)) 
     yo = y; 
     y = 0.5*(y + x ./ y); 
    end 
end 

然后你得到:

>> sqrt_newton(2:9) 
ans = 
    1.4142 1.7321 2.0000 2.2361 2.4495 2.6458 2.8284 3.0000 

>> ans.^2-(2:9) 
ans = 
    1.0e-14 * 
    -0.0444 -0.0444   0 0.0888 -0.0888 0.0888 -0.1776   0 

如预期的那样。不过,我不会推荐它,因为您正在对已经收敛的元素进行不必要的操作。我只是用一个for遍历x在函数的开始:

function yall = sqrt_newton(xall) 
yall = zeros(size(xall)); 
for xn=1:numel(xall) 
    x = xall(xn); 
    y = x/2; 
    yo = y; 
    y = 0.5*(y + x ./ y); 
    while abs(y - yo) > eps * abs(y) 
     yo = y; 
     y = 0.5*(y + x ./ y); 
    end 
    yall(xn)=y; 
end 
end 

在开始设置大小yall,以避免它在整个循环的尺寸增大。