2017-01-02 10 views
0

Уравнение ^−0.2sin(+2) = 0.1 имеет три решения в интервале 0<<10. Найдите эти три решения. (Ответы: = 1.0187, 4.5334, 7.0066).Как найти корень функции

Как я могу получить все корни? Я использовал функцию fzero следующим образом:

fun = @(x) (exp(-0.2.*x).*sin(x+2)); 
x = 0:.01:10; 
z0 = fzero(fun, 0) 
+0

И что делает ваш код? –

ответ

0

Функция fzero останавливается, когда он находит первый нуль. В том, как вы закодировали, этот нуль будет самым близким к «0» (второй параметр).

Вы найдете эти ссылки полезными, так как вопросы очень похожи. Решение состоит в том, чтобы обойти функцию fzero.

https://www.mathworks.com/matlabcentral/answers/103169-how-do-i-find-all-the-zeros-of-a-function

https://www.mathworks.com/matlabcentral/answers/18398-getting-3-zeros-from-a-function-using-fzero

1

хорошие результаты также приведены в: https://es.mathworks.com/matlabcentral/answers/143643-fzero-function-calculating-all-zeros-within-interval

Решение состоит в 3 этапа:

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

    fun [email protected](x) exp(-0.2.*x).*sin(x+2) - 0.1; 
    x = linspace(0,10); 
    y = fun(x); 
    zx = x(fun(x).*circshift(fun(x),[0 -1]) <= 0); % Estimate zero crossings 
    
  2. шаг: Удалить последнюю запись

    zx = zx(1:end-1); % Eliminate any due to ‘wrap-around’ effect 
    
  3. шаг: вычислить все корни в нулевых пересечений

    for k1 = 1:length(zx) 
        fz(k1) = fzero(fun, zx(k1)); 
    end 
    
+0

Большое спасибо M_Tornack. – robax

+1

@robax - если этот ответ решает вашу проблему ** примите ** это. Приветствия не нужны. – EBH

0

В общей численной задачи, это действительно трудно.

Вам нужно сделать некоторые предположения, чтобы помочь fsolve() (неявный ответ M_Tornack). Например, предположим, что грубый поиск сетки некоторого допуска находит все пересечения нуля. Допуск определяет минимальное разделение нулей. Поиск сетки медленный и неточный, поэтому мы уточняем ответы с fsolve впоследствии. В следующем порядке:

fun = @(x) (exp(-0.2.*x).*sin(x+2))-0.1; 
x = 0:0.1:10; % interval start : minimum separation of zeroes : end 
zeros_approx = x(find(diff(fun(x)>0))) % grid search 
for i = 1:length(zeros_approx) 
    zeros_refined(i) = fsolve(fun,zeros_approx(i)) 
end 

В зависимости от вашей проблемы, вы можете проверить свои границы и для нулевых решений. Другой способ - выполнить поиск сетки итеративно, то есть начать с грубой сетки, а затем уточнить приближенные нули.

2

Я собираюсь предоставить канонический ответ на этот вопрос, потому что его часто задают так или иначе - и не только здесь, на переполнении стека.

Если вы заранее знаете, что ваша функция плавная и непрерывная, вы можете использовать метод, используемый Стивеном Моррисом в this File Exchange submission, который я немного поработал для повышения эффективности и ясности.

Его метод приближает функцию к интересующему интервалу по его Chebyshev polynomial. Это дает приближенно-оптимальное приближение с минимальными оценками функций.Корни этого многочлена можно легко найти с помощью метода, близкого к собственной функции MATLAB roots.

Вот переработана функция:

% FINDREALROOTS  Find approximations to all real roots of any function 
%     on an interval [a, b]. 
% 
% USAGE: 
% Roots = FindRealRoots(funfcn, a, b, n, vectorized, make_plot) 
% 
% FINDREALROOTS() approximates all the real roots of the function 'funfcn' 
% in the interval [a,b]. It does so by finding the roots of an [n]-th degree 
% Chebyshev polynomial approximation, via the eigenvalues of the associated 
% companion matrix. 
% 
% When the argument [vectorized] is [true], FINDREALROOTS() will evaluate 
% the function 'funfcn' at all [n] required points in the interval 
% simultaneously. Otherwise, it will use ARRAYFUN() to calculate the [n] 
% function values one-by-one. [vectorized] defaults to [false]. 
% 
% When the argument [make_plot] is true, FINDREALROOTS() plots the 
% original function and the Chebyshev approximation, and shows any roots on 
% the given interval. Also [make_plot] defaults to [false]. 
% 
% All [Roots] (if any) will be sorted. 
% 
% See also roots, eig. 
function Roots = FindRealRoots(funfcn, a, b, n, vectorized, make_plot) 

% First version 26th May 2007 by Stephen Morris, 
% Nightingale-EOS Ltd., St. Asaph, Wales. 
% 
% Modified 2017/January/02 by Rody Oldenhuis, LuxSpace sarl 

    % parse input and initialize. 
    inarg = nargin; 
    if n <= 2, n = 3; end     % Minimum [n] is 3:  
    if (inarg < 5), vectorized = false; end % default: function isn't vectorized 
    if (inarg < 6), make_plot = false; end % default: don't make plot 

    % some convenient variables 
    bma = (b-a)/2; 
    bpa = (b+a)/2; 
    Roots = []; 

    % Obtain the Chebyshev coefficients for the function 
    % 
    % Based on the routine given in Numerical Recipes (3rd) section 5.8; 
    % calculates the Chebyshev coefficients necessary to approximate some 
    % function over the interval [a,b] 

    % initialize 
    c = zeros(1,n); 
    k = (1:n)'; 
    y = cos(pi*((1:n)-1/2)/n); 

    % evaluate function on Chebychev nodes 
    if vectorized 
     f = feval(funfcn, y*bma + bpa); 
    else 
     f = arrayfun(@(x) feval(funfcn,x), y*bma + bpa); 
    end 

    % compute the coefficients 
    for jj = 1:n 
     c(jj) = (f(:).' * (cos((pi*(jj-1)) * ((k-0.5)/n)))) * (2-(jj==1))/n; 
    end  

    % Coefficients may be [NaN] if [inf] 
    if any(~isfinite(c(:))) || (c(n) == 0) 
     return; end 

    % Define [A] as the Frobenius-Chebyshev companion matrix. This is based 
    % on the form given by J.P. Boyd, Appl. Num. Math. 56 pp.1077-1091 (2006). 
    one   = ones(n-3,1); 
    A   = diag([one/2; 0],-1) + diag([1; one/2],+1); 
    A(end, :) = -c(1:n-1)/2/c(n); 
    A(end,end-1) = A(end,end-1) + 0.5; 

    % Now we have the companion matrix, we can find its eigenvalues using the 
    % MATLAB built-in function. We're only interested in the real elements of 
    % the matrix: 
    eigvals = eig(A); 
    realvals = eigvals(imag(eigvals)==0); 

    % if there aren't any real roots, return 
    if isempty(realvals) 
     return; end 

    % Of course these are the roots scaled to the canonical interval [-1,1]. We 
    % need to map them back onto the interval [a, b]; we widen the interval just 
    % a tiny bit to make sure that we don't miss any that are right on the 
    % boundaries. 
    rangevals = nonzeros(realvals(abs(realvals) <= 1+1e-5)); 

    % also sort the roots 
    Roots = sort(rangevals*bma + bpa); 

    % As a sanity check we'll plot out the original function and its Chebyshev 
    % approximation: if they don't match then we know to call the routine again 
    % with a larger 'n'. 
    if make_plot 

     % simple grid 
     grid = linspace(a,b, max(25,n)); 

     % evaluate function like before 
     if vectorized 
      fungrid = feval(funfcn, grid); 
     else 
      fungrid = arrayfun(@(x) feval(funfcn,x), grid); 
     end   
     % corresponding Chebychev-grid (more complicated but essentially 
     % identical) 
     y = (2.*grid-a-b) ./ (b-a); 
     d = zeros(1,length(grid)); 
     dd = d; 
     for j = length(c):-1:2 
      sv=d; 
      d=(2*y.*d)-dd+c(j); 
      dd=sv; 
     end 
     chebgrid = (y.*d) - dd + c(1); 

     % Now make plot 
     figure(1), clf, hold on 
     plot(grid, fungrid ,'color' , 'r'); 
     line(grid, chebgrid,'color' , 'b'); 
     line(grid, zeros(1,length(grid)), 'linestyle','--') 
     legend('function', 'interpolation') 

    end % make plot 

end % FindRealRoots 

Следующий скрипт использует эту функцию, чтобы решить вашу проблему. Поскольку ваша функция довольно тривиальна брать производные, я собираюсь показать, как fzero сравнивает Newton's method, Halley's method и 4th order Householder method:

% Parameters 
N = 9; % Degree of the Chebyshev polynomial to use 
xmin = 0; % LB 
xmax = 10; % UB 

% Function of interest, and its first 3 derivatives 
f = @(x) +exp(-0.2*x) .*  sin(x+2)     - 0.1; 
fp = @(x) +exp(-0.2*x) .* ( cos(x+2) - 0.200*sin(x+2)); 
fpp = @(x) -exp(-0.2*x) .* (0.40*cos(x+2) + 0.960*sin(x+2)); 
fppp = @(x) +exp(-0.2*x) .* (-0.88*cos(x+2) + 0.592*sin(x+2)); 

% Approximate the roots 
R = FindRealRoots(f, xmin, xmax, N, true, false); 

% Refine the roots 
% Compare fzero against the first 3 Householder methods 
A = R; fevals_fzero = N; 
B = R; fevals_Newton = N; 
C = R; fevals_Halley = N; 
D = R; fevals_4th = N; 

options = optimset('TolX' , 1e-10,... 
        'display', 'off'); 

for ii = 1:numel(A) 

    % FZERO 
    [A(ii), ~,~, out] = fzero(f, R(ii), options);  
    fevals_fzero = fevals_fzero + out.funcCount; 

    % Newton's method 
    xprev = inf; 
    x  = R(ii);  
    while (abs(xprev - x) > 1e-10) 
     xprev = x; 
     x  = x - f(x)/fp(x); 
     fevals_Newton = fevals_Newton + 2; 
    end  
    B(ii) = x; 

    % Halley's method 
    xprev = inf; 
    x  = R(ii);  
    while (abs(xprev - x) > 1e-10) 

     fx = f(x); 
     fpx = fp(x); 
     fppx = fpp(x); 

     xprev = x; 
     x  = x - 2*fx*fpx/(2*fpx*fpx - fx*fppx); 

     fevals_Halley = fevals_Halley + 3; 
    end  
    C(ii) = x; 

    % 4th order method 
    xprev = inf; 
    x  = R(ii);  
    while (abs(xprev - x) > 1e-10) 

     fx = f(x); fx2 = fx*fx; 
     fpx = fp(x); fpx2 = fpx*fpx; 
     fppx = fpp(x); 
     fpppx = fppp(x); 

     xprev = x; 
     x  = x - 3*(2*fx*fpx2 - fx2*fppx)/... 
        (6*(fpx2*fpx - fx*fpx*fppx) + fx2*fpppx); 

     fevals_4th = fevals_4th + 4; 
    end  
    D(ii) = x; 

end 

% Check for convergence 
all_equal = all(abs(A-B) < 1e-8) && ... 
      all(abs(A-C) < 1e-8) && ... 
      all(abs(A-D) < 1e-8) 

% function evaluations per method 
fevals_fzero 
fevals_Newton 
fevals_Halley 
fevals_4th 

Рисунок генерируется, когда последний аргумент FindRealRoots установлен в true:

линейный выход

Chebyshev approximant

Команда:

all_equal = 
1 
fevals_fzero = 
    29 
fevals_Newton = 
    27 
fevals_Halley = 
    36 
fevals_4th = 
    41 

Выводы:

  • Для гладких непрерывных функций, полином Чебышева является достаточно эффективным и достаточно для большинства намерений и целей. В этом примере здесь использовались только 9 оценок функций, чтобы найти (1) количество корней и (2) начальные оценки для каждой из них с точностью до 2 цифр. Эти цифры улучшаются только для увеличения полиномиального порядка. Для этой конкретной функции точность улучшается за счет меньших вычислительных затрат, чем любого из из более «стандартных» методов уточнения, продемонстрированных здесь. Установка порядка полинома примерно до 19 (подразумевает 19 оценок функций) дает сопоставимую точность и производительность, поэтому не уточняется на самом деле необходимо.
  • fzero прост в использовании, но, конечно, не самый лучший при любых обстоятельствах. В этом конкретном случае метод Ньютона тривиален для настройки и имеет лучшую производительность.
  • Не полагайтесь слишком сильно на утверждения о скорости конвергенции численного метода; это теоретический предел, который сам по себе не доказывает превосходство метода, используемого на практике. В вышесказанном показано, что чем выше порядок метода уточнения, тем выше производительность.