Функция Matlab неожиданно ведет себя на массиве входов - PullRequest
0 голосов
/ 24 сентября 2019

Я сделал функцию (деление пополам), которая вычисляет ноль функции (например, 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

do_bisection

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);

Ответы [ 2 ]

0 голосов
/ 24 сентября 2019

Ваш код работает нормально, и ваш алгоритм деления пополам выглядит правильно.Появляется предупреждающее сообщение из-за вызова функции fplot .

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

Эта функция автоматически отображает функцию f, определенную как дескриптор функции.Однако он предупреждает, что ваша функция f неправильно векторизована .Чтобы избавиться от предупреждения, просто измените определение вашей функции

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 автоматически учитывает размер массива.

Только с этими изменениями функция работает нормально без предупреждений и выдает желаемый результат:

enter image description here

0 голосов
/ 24 сентября 2019

Вы можете отладить это ...

Полное предупреждение выглядит следующим образом:

Предупреждение. Функция неожиданно работает на входах массива.Чтобы повысить производительность, правильно векторизуйте вашу функцию, чтобы она возвращала выходные данные того же размера и формы, что и входные аргументы.
[...]
В fplot (строка 161)
В бисекции (строка 70)

Это строка 70 из bisection:

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

Вы предоставляете функцию @(x)0, которая возвращает скаляр 0 для векторного ввода (который создает fplot).Поэтому ошибка имеет смысл, вы вводите массив в @(x)0, который неправильно обрабатывает массивы!

Два решения:

  1. Правильно определите свою анонимную функцию для обработки входов массива x

    fplot( @(x) zeros(size(x)), [x0(1), x0(2)], 'r-' );
    
  2. Используйте более быструю функцию, чем fplot, чтобы просто нарисовать линию в y=0 между вашими двумя x0 баллов.

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

Я предлагаю plot, потому что все, что вы пытаетесь сделать, это построить прямую линию между двумя точками.fplot создает массив под капотом, чтобы сделать это для вас, но здесь это излишне, а plot - более простая функция!Вы также можете использовать line, который еще проще, но имеет немного другой синтаксис для определения стилей.

Аналогично, вам нужно изменить определение f, чтобы правильно обрабатывать массивы с помощью элемента .мудрый энергетик :

f = @(x) x.^2 - 5;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...