sexta-feira, 19 de maio de 2017

Encontrando a raiz de uma função: método das secantes


O cálculo da raiz de uma função, isto é, o valor de $x$ tal que $f(x) = 0$ pode ser calculado pelo método de Newton-Raphson:
$$ x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} $$
Como o cálculo da derivada da função ($f'(x)$) pode ser trabalhoso ou difícil de calcular, em seu lugar pode ser usado uma aproximação numérica, como, por exemplo, a diferença dividida regressiva:
$$ f'(x_n) = \frac{f(x_{n-1}) - f(x_n)}{x_{n-1} - x_n}$$
que leva ao método da secante:
$$ x_{n+1} = x_n - \frac{f(x_n)(x_{n-1} - x_n)}{f(x_{n-1}) - f(x_n)} $$
Entretanto, a derivada de uma função também pode ser aproximada por:
$$ f'(x_n) = \frac{f(x_n+h)-f(x_n)}{h} $$
ou ainda
$$ f'(x_n) = \frac{f(x_n+h)-f(x_n-h)}{2h} $$
onde $h$ é um valor pequeno, por exemplo: $h = 10^{-3}$. O código Scilab abaixo mostra uma comparação entre essas formas de implementar o método da secante para o cálculo do zero da função $x e^{-x/2} - x^2/2$ que está entre $1,1$ e $1,2$.

Código:


function ff=fco(x)  // função
    ff = x.*exp(-x/2) - x.*x/2;
endfunction

function ffd=dfco(x)   // derivada da função
    h = 1e-6;
    ffd = exp(-x/2) - 0.5*x.*exp(-x/2) - x;
endfunction

clc; 

t = 0:0.01:1.5;
y1 = t.*exp(-t/2);
y2 = t.*t/2;
y3 = dfco(t);
close; plot(t,y1,t,y2,t,y1-y2,t,y3); xgrid;

erromax = 1e-16;

disp(' **** Secante: ');
erro = 1;
h = 1e-3;
t1 = 1.2;
t2 = 1.1;
k = 1;
while abs(erro) > erromax
    dff = fco(t1) - fco(t2);
    erro = fco(t2)*(t1 - t2)/dff;
    t1 = t2;
    t2 = t2 - erro;
    disp([k, t2, erro]);
    k = k + 1;
    if k>10 then erro = 0; end;
end

disp('  *****  Secante d1:');

erro = 1;
h = 1e-3;
t = 1.1
k = 1;
while abs(erro) > erromax
    dff = (fco(t+h) - fco(t))/(h);
    erro = fco(t)/dff;
    t = t - erro;
    disp([k, t, erro]);
    k = k + 1;
    if k>10 then erro = 0; end;
end

disp('  ***** Secante d2:');

erro = 1;
h = 1e-3;
t = 1.1
k = 1;
while abs(erro) > erromax
    dff = (fco(t+h) - fco(t-h))/(2*h);
    erro = fco(t)/dff;
    t = t - erro;
    disp([k, t, erro]);
    k = k + 1;
    if k>10 then erro = 0; end;
end

disp(' *****  Newton:');

erro = 1;
h = 1e-3;
t = 1.1
k = 1;
while abs(erro) > erromax
    dff = dfco(t);
    erro = fco(t)/dff;
    t = t - erro;
    disp([k, t, erro]);
    k = k + 1;
    if k>10 then erro = 0; end;
end


Resultados:

**** Secante: 
   1.   1.1325514  -0.0325514
   2.   1.1343352  -0.0017838
   3.   1.1342865   0.0000487
   4.   1.1342866  -6.681D-08
   5.   1.1342866  -2.568D-12
   6.   1.1342866   0.

   *****  Secante d1:
   1.   1.135246  -0.035246
   2.   1.1342881   0.000958
   3.   1.1342866   0.0000015
   4.   1.1342866   1.173D-09
   5.   1.1342866   9.277D-13
   6.   1.1342866   8.737D-16
   7.   1.1342866   0.

   ***** Secante d2:
   1.   1.1352758  -0.0352758
   2.   1.1342874   0.0009884
   3.   1.1342866   0.0000008
   4.   1.1342866   4.226D-13
   5.   1.1342866   0.

  *****  Newton:
   1.   1.1352758  -0.0352758
   2.   1.1342874   0.0009884
   3.   1.1342866   0.0000008
   4.   1.1342866   4.727D-13
   5.   1.1342866   0.


Conclusão.

Para este exemplo, o método da secante usando a aproximação da derivada $f'(x) = (f(x+h) - f(x-h))/(2h)$ (método d2) é tão rápido quanto o método de Newton. Já o método da secante usando a aproximação $f'(x) = (f(x+h) - f(x))/h$ (método d1) foi o mais lento. Se o passo $h$ usado fosse maior ($h = 10^{-2}$, por exemplo), o método d1 seria ainda mais lento.

Nenhum comentário:

Postar um comentário