7. Implementação do método da secante#

Neste capítulo, utilizamos uma implementação própria do método da secante para resolver equações não-lineares unidimensionais. O algoritmo é capaz de lidar com uma quantidade razoável de funções matemáticas.

Para ser executado, o método secante requer 5 parâmetros:

  • estimativas iniciais xa e xb;

  • a função f(x) propriamente dita, representada por f;

  • o erro relativo desejado ER, representado por tol;

  • o número máximo de iterações N para tentativa de solução, representado por N.

import inspect, re
import numpy as np
import matplotlib.pyplot as plt
from prettytable import PrettyTable as pt

def secante(xa,xb,f,tol,N):
    """Algoritmo para determinação de raízes pelo método da secante.

    Parâmetros: 
        f: string dependendo de uma variável, i.e., a função-alvo
            (e.g., 'x**2 - 1', 'x**2*cos(x)', etc.) 
        xa: 1a. estimativa 
        xb: 2a. estimativa        
        tol: erro relativo desejado (tolerância)
        N: número máximo de iterações a repetir

    Retorno: 
        x: aproximação para a raiz da função
    """

    # construtor de tabela
    table = pt()
    
    # substitui expressões da string pelas chamadas das funções do numpy
    f = re.sub('(sin|sinh|cos|cosh|tan|tanh|exp|log|sqrt|log10|arcsin|arccos|arctan|arcsinh|arccosh|arctanh)', r'np.\1', f)    
    
    # identifica a variável independente em f
    var = re.search(r'([a-zA-Z][\w]*) ?([\+\-\/*]|$|\))', f).group(1)
    
    # cria função
    f = eval('lambda ' + var + ' :' + f)
    
    # checa se a função é de uma variável, senão lança erro        
    try: 
        len(inspect.getfullargspec(f).args) - 1 > 0
    except:
        raise ValueError('O código é válido apenas para uma variável.')
    
    it = 0 # contador de iteracoes
    
    # cabeçalho de tabela
    table.field_names = ['i','x','f(x)','ER']

    # imprime estimativa inicial
    print(f'Estimativas iniciais: xa = {xa:.6f}; xb = {xb:.6f}\n')  

    # Loop 
    for i in range(0,N):
        
        x = (xa*f(xb) - xb*f(xa))/(f(xb) - f(xa))
        
        e = abs(x-xb)/abs(x) # erro
        
        # tabela
        # impressão de tabela
        table.add_row([i,np.round(x,8),np.round(f(x),8),f'{e:e}'])
        table.align = 'c';      
        
        if e < tol:
            break
        xa = xb
        xb = x                
        
    print(table)
       
    if i == N:
        print(f'Solução não obtida em {N:d} iterações')
    else:
        print(f'Solução obtida: x = {x:.6f}')

    return x

7.1. Problema#

Determinar a raiz positiva da equação: f(x)=x2e2x, pelo método das secantes com erro inferior a 105.

7.1.1. Resolução#

Para obter os valores iniciais x0 e x1 necessários ao processo iterativo do método das secantes, fazemos a análise gráfica.

def f(x):
    return np.sqrt(x) - 2*np.exp(-2*x) 
  
x = np.linspace(0,3,100)
plt.figure(figsize=(6,3))
plt.plot(x,f(x),label='$f(x) = \\sqrt{x} - 2e^{-2x}$');
plt.axhline(y=0,color='r',linestyle=':')
plt.legend();
_images/aula-07-secante_6_0.png

Verificamos que a raiz encontra-se próxima a 0.5

f(0.5)
-0.028652101156337095

Assim, podemos escolher duas estimativas iniciais próximas deste valor, digamos x0=0.5δx e x1=0.5+δx, com δx=101.

x0, dx = 0.5, 1e-1
x = secante(x0 - dx,x0 + dx,'sqrt(x) - 2*exp(-2*x)',1e-5,100)
Estimativas iniciais: xa = 0.400000; xb = 0.600000

+---+------------+-------------+--------------+
| i |     x      |     f(x)    |      ER      |
+---+------------+-------------+--------------+
| 0 | 0.52143975 |  0.01723111 | 1.506603e-01 |
| 1 | 0.51270504 | -0.00126447 | 1.703652e-02 |
| 2 | 0.5133022  |   8.57e-06  | 1.163365e-03 |
| 3 | 0.51329818 |     0.0     | 7.829741e-06 |
+---+------------+-------------+--------------+
Solução obtida: x = 0.513298

7.2. Exemplo#

Resolva o problema f(x)=0, para f(x)=arccos(x)+4sen(x)+1.7, no intervalo 0.2x1.0 e ϵ=103.

x0, dx = -0.8, 1e-1
x = secante(x0 - dx,x0 + dx,'-arccos(x) + 4*sin(x) + 1.7',1e-3,20)
Estimativas iniciais: xa = -0.900000; xb = -0.700000

+---+-------------+-------------+--------------+
| i |      x      |     f(x)    |      ER      |
+---+-------------+-------------+--------------+
| 0 |  0.01559341 |  0.20716881 | 4.589077e+01 |
| 1 | -0.02762483 | -0.00890993 | 1.564471e+00 |
| 2 | -0.02584274 |   -1.4e-06  | 6.895899e-02 |
| 3 | -0.02584246 |     0.0     | 1.082134e-05 |
+---+-------------+-------------+--------------+
Solução obtida: x = -0.025842

Resolvemos usando outras estimativas iniciais.

x0, dx = -0.9, 1e-3
x = secantes(x0 - dx,x0 + dx,'-arccos(x) + 4*sin(x) + 1.7',1e-3,20)
Estimativas iniciais: xa = -0.901000; xb = -0.899000

+---+-------------+-------------+--------------+
| i |      x      |     f(x)    |      ER      |
+---+-------------+-------------+--------------+
| 0 | -0.03737686 | -0.05765454 | 2.305231e+01 |
| 1 | -0.02514562 |  0.00348352 | 4.864164e-01 |
| 2 | -0.02584253 |   -3.5e-07  | 2.696761e-02 |
| 3 | -0.02584246 |     -0.0    | 2.747395e-06 |
+---+-------------+-------------+--------------+
Solução obtida: x = -0.025842