O zero de uma função f(x)f(x) é qualquer valor ξ\xi tal que f(ξ)=0f(\xi) = 0. É a raiz da equação. É onde a curva cruza o eixo xx.

Para polinômios de segundo grau, existe fórmula fechada. Para grau 3 ou 4, existem fórmulas mas são complicadas. Para grau 5 em diante, não existe fórmula geral.

É exatamente nesses casos que o cálculo numérico entra.

Todo método de busca de raízes funciona em duas etapas:

Fase I - Isolamento: encontrar um intervalo [a,b][a, b] que com certeza contém uma raiz.

Fase II - Refinamento: a partir desse intervalo, ir melhorando a aproximação até atingir a precisão que você quer.

O isolamento se apoia no Teorema do Valor Intermediário (TVI): se ff é contínua em [a,b][a, b] e os sinais nos extremos são opostos,

f(a)f(b)<0f(a) \cdot f(b) < 0

então existe pelo menos um ξ\xi entre aa e bb onde f(ξ)=0f(\xi) = 0. É intuitivo, se a função começa positiva e termina negativa, ela teve que cruzar o zero em algum ponto.

Teorema do Valor Intermediário - f(x) = (x−1)(x−3)
Veja como o sinal nos extremos determina a garantia de existência de raiz
-1012301234abf(a)f(b)ξ
f(a)
3.00
f(b)
-1.00
f(a) · f(b)
-3.00
Sinais opostos - o TVI garante pelo menos uma raiz dentro de [a, b].

Método da Bissecção: dividir para conquistar

Você tem um intervalo [a,b][a, b] com uma raiz dentro. Calcula o ponto do meio

x0=a+b2x_0 = \frac{a + b}{2}

e avalia f(x0)f(x_0).

Aí três coisas podem acontecer:

  • f(x0)=0f(x_0) = 0 -> achou a raiz, acabou
  • f(a)f(x0)<0f(a) \cdot f(x_0) < 0 -> a raiz está em [a,x0][a, x_0], descarta a metade direita
  • f(x0)f(b)<0f(x_0) \cdot f(b) < 0 -> a raiz está em [x0,b][x_0, b], descarta a metade esquerda

Repete até o intervalo ser menor que a precisão ε\varepsilon que você definiu.

1
# Pseudo-código do método da Bissecção
2
3
dado f, a, b, ε:
4
enquanto (b - a) > ε:
5
x = (a + b) / 2
6
se f(a) * f(x) < 0:
7
b = x
8
senão:
9
a = x
10
retorna x
Método da Bissecção — f(x) = x·log10(x) − 1
Intervalo inicial [2, 3] · precisão ε = 10-5
-0.400.422.53abx
a
2.0000000
x = (a+b)/2
2.5000000
b
3.0000000
f(x)
-0.00514998
|b − a| = 1.0000000
Iteração 0 / 16
f(x) intervalo [a, b] x = (a+b)/2 raiz real ≈ 2.50618

Quantas iterações vai precisar?

Dá para calcular antes de rodar. O intervalo encolhe pela metade a cada iteração, então depois de kk passos o tamanho é ba2k\frac{b - a}{2^k}. Para garantir precisão ε\varepsilon:

k>log(b0a0)log(ε)log(2)k > \frac{\log(b_0 - a_0) - \log(\varepsilon)}{\log(2)}

Com [2,3][2, 3] e ε=105\varepsilon = 10^{-5}, precisamos de menos de 17 iterações. O método é convergente, vai sempre chegar lá, só não é o mais rápido.

Implementando em Python

bisseccao.py
1
import math
2
3
def f(x):
4
return x * math.log10(x) - 1
5
6
def bisseccao(f, a, b, eps=1e-5):
7
if f(a) * f(b) >= 0:
8
raise ValueError("f(a) e f(b) precisam ter sinais opostos")
9
10
k = 0
11
while (b - a) > eps:
12
x = (a + b) / 2
13
if f(a) * f(x) < 0:
14
b = x
15
else:
16
a = x
17
k += 1
18
print(f"Iteração {k:2d}: x = {x:.8f}, f(x) = {f(x):.2e}")
19
20
return (a + b) / 2
21
22
raiz = bisseccao(f, 2, 3)
23
print(f"\nRaiz encontrada: {raiz:.6f}")

Rodando para f(x)=xlog10(x)1f(x) = x \cdot \log_{10}(x) - 1 no intervalo [2,3][2, 3]:

1
Iteração 1: x = 2.50000000, f(x) = -5.15e-03
2
Iteração 2: x = 2.75000000, f(x) = 2.08e-01
3
Iteração 3: x = 2.62500000, f(x) = 1.00e-01
4
Iteração 4: x = 2.56250000, f(x) = 4.72e-02
5
Iteração 5: x = 2.53125000, f(x) = 2.09e-02
6
Iteração 6: x = 2.51562500, f(x) = 7.87e-03
7
Iteração 7: x = 2.50781250, f(x) = 1.36e-03
8
Iteração 8: x = 2.50390625, f(x) = -1.90e-03
9
Iteração 9: x = 2.50585938, f(x) = -2.71e-04
10
Iteração 10: x = 2.50683594, f(x) = 5.43e-04
11
Iteração 11: x = 2.50634766, f(x) = 1.36e-04
12
Iteração 12: x = 2.50610352, f(x) = -6.72e-05
13
Iteração 13: x = 2.50622559, f(x) = 3.45e-05
14
Iteração 14: x = 2.50616455, f(x) = -1.63e-05
15
Iteração 15: x = 2.50619507, f(x) = 9.10e-06
16
Iteração 16: x = 2.50617981, f(x) = -3.61e-06
17
Iteração 17: x = 2.50618744, f(x) = 2.74e-06
18
19
Raiz encontrada: 2.506184

Vantagens e limitações

O método da Bissecção é robusto: desde que ff seja contínua e os sinais sejam opostos, ele sempre converge.

A desvantagem é a velocidade, outros métodos como Newton-Raphson têm convergência mais rápida, mas exigem calcular derivadas e podem divergir se o chute inicial for ruim.

Para muitas aplicações práticas, a bissecção já resolve muito bem. É o método que você usa quando quer garantia, não velocidade.