Python para Zero de Funções
Neste capítulo, o Python será usado para transformar as ideias dos métodos de Bisseção, Cordas e Newton em algoritmos controlados por intervalo, aproximação e tolerância. Como os comandos básicos já foram apresentados na introdução ao Python, aqui o foco será organizar funções, critérios de parada, registros de iterações e validações numéricas.
Definindo uma função
Nos métodos de zero de funções, a função deve receber um número real e devolver outro número real. Isso permite testar sinais, calcular aproximações e medir resíduos. Por exemplo, para \(f(x)=x^3-10\):
def f(x):
return x**3 - 10
print(f(2))
print(f(3))
Ao programar os métodos, é útil manter a função separada do algoritmo. Assim, o mesmo código da Bisseção, das Cordas ou de Newton pode ser reaproveitado para outra função, mudando apenas a definição de f.
Funções matemáticas
Quando a expressão usa seno, cosseno, exponencial ou raiz quadrada e será avaliada em um ponto por vez, podemos importar funções da biblioteca math:
from math import cos, sin, exp, sqrt
def f(x):
return 2*x**3 - 2*x - cos(x**3) - 1
| Matemática | Python | Exemplo |
|---|---|---|
| \(\sqrt{x}\) | sqrt(x) |
raiz quadrada |
| \(\cos(x)\) | cos(x) |
cosseno |
| \(e^x\) | exp(x) |
exponencial |
Validação do intervalo
Antes de aplicar um método fechado, como a Bisseção, é importante validar o intervalo. Se \(f(a)\cdot f(b)<0\), há mudança de sinal entre os extremos. Em Python, podemos transformar esse teste em uma função auxiliar:
def tem_mudanca_sinal(f, a, b):
return f(a) * f(b) < 0
if tem_mudanca_sinal(f, 2, 3):
print("Intervalo válido para Bisseção")
else:
print("Escolha outro intervalo")
Essa validação evita iniciar o algoritmo com uma hipótese incompatível com o método. Ela não garante que exista apenas uma raiz no intervalo, mas confirma a condição usada pelo teorema do valor intermediário.
Valor médio do intervalo
No método da Bisseção, calculamos o ponto médio do intervalo:
\[m = \frac{a+b}{2}\]m = (a + b) / 2
print(m)
Critérios de parada
Os métodos numéricos repetem aproximações até que algum erro fique menor que a tolerância. Em zero de funções, dois critérios comuns são o tamanho do intervalo e o resíduo \(|f(x)|\):
a = 2
b = 3
m = (a + b) / 2
erro_intervalo = abs(b - a)
erro_funcao = abs(f(m))
tolerancia = 0.001
parar = erro_intervalo < tolerancia or erro_funcao < tolerancia
Também é recomendável limitar o número de iterações. Isso impede que o programa fique preso quando a função, o intervalo ou a tolerância foram escolhidos de forma inadequada.
max_iteracoes = 50
iteracao = 0
while iteracao < max_iteracoes:
m = (a + b) / 2
if abs(f(m)) < tolerancia or abs(b - a) < tolerancia:
break
if f(a) * f(m) < 0:
b = m
else:
a = m
iteracao = iteracao + 1
Registrando as iterações
Para montar tabelas de cálculo, podemos guardar os principais valores de cada iteração em uma lista de dicionários. Essa estrutura facilita imprimir, conferir e comparar os resultados:
historico = []
historico.append({
"iteracao": iteracao,
"a": a,
"b": b,
"m": m,
"f_m": f(m),
"erro": abs(b - a)
})
Derivadas com SymPy
No método de Newton, precisamos da derivada da função. A biblioteca sympy permite calcular a derivada simbólica e depois convertê-la em uma função numérica usando lambdify:
import sympy as sp
x = sp.symbols("x")
expressao = x**3 - 10
derivada = sp.diff(expressao, x)
f = sp.lambdify(x, expressao, "math")
df = sp.lambdify(x, derivada, "math")
x_atual = 2
x_proximo = x_atual - f(x_atual) / df(x_atual)
print(x_proximo)
Essa separação entre expressão simbólica, função numérica e derivada numérica ajuda a reduzir erros de transcrição na implementação do método de Newton.
Atividade
Para \(f(x)=x^2-4\), crie uma função auxiliar que valide a mudança de sinal em \([1,3]\), calcule o ponto médio e registre em um dicionário os valores de \(a\), \(b\), \(m\), \(f(m)\) e \(|b-a|\).