【问题标题】:Matlab Function Behaves Unexpectedly on Array of InputsMatlab 函数在输入数组上的行为异常
【发布时间】:2019-09-24 23:59:57
【问题描述】:

我创建了一个函数(二分法),它使用二分法计算函数的零(如 fzero),但是当我运行该函数时,我收到以下警告: “警告:函数在数组输入上的行为异常。为了提高性能,请正确矢量化您的函数以返回与输入参数具有相同大小和形状的输出。”

不知道如何解决。

二分函数

function[x, output, graf] = bisection(f, x0, TOL, NMAX)
graf = "no";
if(nargin > 1)
    if (~exist('TOL','var') || TOL == '~')
        TOL = eps;
    end
    if (~exist('NMAX','var') || NMAX == '~')
        NMAX = 500;
     end    
else
    error('Too few input arguments');
end
    if isa(f, 'function_handle')
        % f is a function
    else
        error('f is not a function!');
    end

    if isvector(x0)
        disp(size(x0));
        if (size(x0) > 2)
            error('x0 has too many elements!');
        else 
            if(size(x0) < 2)
                error('x0 has too few elements!');
            end
        end
        if ~isnumeric(x0(1)) || ~isnumeric(x0(2))
            error('Elements of x0 must be numeric!');
        end 
        if x0(1)>x0(2)
            error('x0(1) is > than x0(2)');
        end
    else
        error('x0 is not a vector!');
    end

    if f(x0(1))*f(x0(2)) > 0
        error('There are no zeros!');
    end

    if ~isnumeric(NMAX)
       error('NMAX must be a number'); 
    else 
        if floor(NMAX) ~= NMAX
            error('NMAX must be integer');
        end
    end

    if ~isnumeric(TOL)
       error('TOL must be numeric!');
    end 


    x0 = [x0(1), x0(2)];    
    [x, output] = do_bisection(f,x0,TOL,NMAX);

        output = [ output(1), NMAX - output(2) ];

        if("yes" == "yes")
            fplot(f,[x0(1)*2, x0(2)*2]);
            title(strcat('Grafico f = ',func2str(f)));
            xlabel('x');
            ylabel('y = f(x)');
            grid on;
            grid minor;
            set(gca,'xaxislocation','origin');
            set(gca,'yaxislocation','origin');
            hold on;
            fplot(@(x) 0,[x0(1), x0(2)],'r -');
            plot(x,f(x),'k s');
            text(x0(1), 0.5, strcat('a=',num2str(x0(1))));
            text(x0(2), 0.5, strcat('b=',num2str(x0(2))));
            text(x, -0.5, strcat('x=',num2str(x)));
            graf = "yes";
        end  
end

做二等分

function[x, output] = do_bisection(f, x0, TOL, NMAX)
    a = x0(1);
    b = x0(2);
    if f(a)*f(b)>0 
        error('non ci sono zeri');
    end
    iter = 0;
    c = (a+b)/2;
    while(iter<NMAX && (((abs(x0(2)-x0(1))/max(abs(x0(1)),abs(x0(2))))>TOL) && (abs(f(c)) > eps)))
        if(f(c)*f(a) < 0)
            b = c;
        else
            a = c;
        end
        c = (a +b)/2;
        iter = iter +1;
    end
    x = c;
    output = [ f(c), iter ];
end

我调用函数

f = @(x) x^2 - 5;
x0 = [1, 3];
[x, out, graf] = bisection(f,x0,10.^(-5),500);

【问题讨论】:

    标签: matlab function


    【解决方案1】:

    你可以调试这个...

    完整的警告如下所示:

    警告:函数在数组输入上的行为异常。为了提高性能,请正确矢量化您的函数以返回与输入参数具有相同大小和形状的输出。
    [...]
    在 fplot 中(第 161 行)
    在二等分中(第 70 行)

    bisection 的第 70 行是这一行:

    fplot(@(x) 0,[x0(1), x0(2)],'r -');
    

    您提供的函数是@(x)0,它为向量输入(由fplot 创建)返回一个标量0。因此错误是有道理的,您正在向@(x)0 输入一个数组,它不能正确处理数组!

    两种解决方案:

    1. 正确定义匿名函数来处理数组输入x

      fplot( @(x) zeros(size(x)), [x0(1), x0(2)], 'r-' );
      
    2. 使用比fplot 更快的函数在两个x0 点之间的y=0 处简单地画一条线。

      plot( x0(1:2), [0 0], 'r-' );
      

    我建议plot,因为您要做的只是在两点之间绘制一条直线。 fplot 正在后台创建一个数组来为您执行此操作,但这在这里有点过头了,plot 是一个更简单的函数!您也可以使用line,它更简单,但指定样式的语法略有不同。

    同样,您需要更改f 的定义以使用element-wise power operator 正确处理数组:

    f = @(x) x.^2 - 5;
    

    【讨论】:

    • 非常有用,谢谢!一个问题,我如何获得完整的调试日志?
    • 那个完整的堆栈跟踪应该出现在你的命令窗口中......如果它没有然后尝试运行warning( 'backtrace', 'on' );,你可能已经以某种方式禁用它
    【解决方案2】:

    您的代码运行良好,您的二分算法似乎已正确实现。 出现的警告信息是因为调用了fplot 函数。

    fplot(f,[x0(1)*2, x0(2)*2]);
    

    此函数自动绘制定义为函数句柄的函数f。但是,它会警告您,您的函数 f 不正确 vectorized。要摆脱警告,只需更改您的函数定义

    f = @(x) x^2 - 5;
    

    f = @(x) x.^2 - 5;
    

    请注意,.^ 表示逐元素取幂。如果你只写x^2,MATLAB 会尝试做一个矩阵乘法。

    此警告也将出现在另一个 fplot 呼叫中。将其更改为:

    fplot(@(x) 0.*x,[x0(1), x0(2)],'r -');
    

    你应该没事。这一次,我只是将0 乘以数组x。本质上,结果是相同的。但是,0 乘以 x 会自动考虑数组大小。

    仅通过此更改,该函数运行良好,没有任何警告,并产生所需的输出:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多