Erro e Condicionamento

intermediario computacao-cientifica, otimizacao analise-numerica

Erro e Condicionamento

Há duas perguntas independentes diante de um resultado numérico ruim: o problema é sensível? e o algoritmo é bom? Confundir as duas leva a culpar o código quando a culpa é do problema, ou vice-versa.

Tipos de erro

$$\text{erro absoluto} = |\hat x - x|, \qquad \text{erro relativo} = \frac{|\hat x - x|}{|x|}$$

O erro relativo é quase sempre o que interessa, porque é adimensional e comparável entre escalas. Um erro absoluto de $1$ metro é irrelevante ao medir a distância à Lua e catastrófico ao usinar uma peça.

Fontes de erro:

FonteOrigem
ArredondamentoPrecisão finita da máquina
TruncamentoSubstituir um processo infinito por finito
DadosMedição imprecisa da entrada
ModeloO modelo não descreve a realidade

Os dois primeiros são do domínio da análise numérica; os dois últimos, da modelagem — e frequentemente dominam.

Condicionamento

O número de condição mede quanto o problema amplifica erros da entrada, independentemente do algoritmo:

$$\kappa = \frac{\text{erro relativo na saída}}{\text{erro relativo na entrada}}$$

Para uma função diferenciável:

$$\kappa(x) = \left|\frac{x f'(x)}{f(x)}\right|$$

Para sistemas lineares:

$$\kappa(A) = |A|,|A^{-1}| = \frac{\sigma_1}{\sigma_n}$$

Regra de bolso: com $\kappa \approx 10^k$, perdem-se cerca de $k$ dígitos. Em float64 (16 dígitos), $\kappa = 10^{12}$ deixa quatro dígitos confiáveis; $\kappa = 10^{16}$ não deixa nenhum.

Um problema mal condicionado é intrinsecamente difícil: nenhum algoritmo o resolve bem em precisão finita. A solução não é procurar código melhor — é reformular o problema, regularizar ou aumentar a precisão.

Estabilidade

Estabilidade é propriedade do algoritmo, não do problema. Um algoritmo é estável no sentido regressivo quando o resultado calculado é a solução exata de um problema ligeiramente perturbado:

$$\hat y = f(\tilde x), \qquad \tilde x \approx x$$

Essa é a formulação mais útil, porque separa claramente as responsabilidades. A relação final é:

$$\text{erro direto} \lesssim \kappa \times \text{erro regressivo}$$

Ou seja: algoritmo estável + problema bem condicionado = resultado confiável. Se qualquer um dos dois falhar, o resultado não é.

Exemplos que ilustram a distinção

Problema mal condicionado. Calcular as raízes do polinômio de Wilkinson $\prod_{k=1}^{20}(x-k)$ a partir dos coeficientes. Uma perturbação de $2^{-23}$ num único coeficiente move as raízes em várias unidades. Não há algoritmo que salve — a informação simplesmente não está nos coeficientes.

Algoritmo instável para problema bem condicionado. Calcular a variância por $E[X^2]-(E[X])^2$ com dados de média grande. O problema é bem condicionado; a fórmula é que cancela. O algoritmo de Welford resolve o mesmo problema de forma estável.

Eliminação sem pivoteamento. Resolver $Ax=b$ com $A$ bem condicionada mas pivô pequeno. O problema está bom; o algoritmo é que amplifica o erro. Com pivoteamento parcial, o mesmo problema é resolvido corretamente.

Diagnóstico prático

import numpy as np

k = np.linalg.cond(A)
if k > 1e12:
    print(f'atenção: kappa = {k:.1e}, resultado pouco confiável')

# resíduo pequeno NÃO garante solução precisa
x = np.linalg.solve(A, b)
residuo = np.linalg.norm(A @ x - b) / np.linalg.norm(b)

O último ponto merece ênfase: em problema mal condicionado, um resíduo minúsculo é perfeitamente compatível com uma solução muito errada. Resíduo pequeno indica estabilidade regressiva, não precisão. Verifique o condicionamento antes de confiar.

O que fazer com problema mal condicionado

Reformular. Muitas vezes existe formulação equivalente e melhor condicionada. Usar QR em vez de equações normais reduz $\kappa^2$ a $\kappa$.

Regularizar. Acrescentar $\lambda I$ (Tikhonov / Ridge) limita o condicionamento ao custo de introduzir viés. Truncar valores singulares pequenos na pseudoinversa tem o mesmo efeito.

Escalar. Colunas com unidades de magnitudes muito diferentes inflam artificialmente o condicionamento. Normalizar atributos costuma resolver — é o mesmo motivo pelo qual padronizar entradas acelera o treino de redes neurais.

Aumentar a precisão. float128 ou aritmética arbitrária compram dígitos, ao custo de desempenho.

Exemplo trabalhado

$$A = \begin{pmatrix} 1 & 1 \ 1 & 1{,}0001 \end{pmatrix}$$

As linhas são quase paralelas, então $A$ é quase singular. Seu número de condição é da ordem de $4\times10^4$, o que significa perder cerca de 4 ou 5 dígitos.

Geometricamente: as duas retas do sistema se cruzam num ângulo minúsculo, e mover qualquer uma delas ligeiramente desloca muito o ponto de interseção. Nenhum algoritmo contorna isso.

Erros comuns

  • Culpar o algoritmo por um problema mal condicionado.
  • Confiar em resíduo pequeno como prova de precisão.
  • Não escalar os dados e inflar o condicionamento sem necessidade.
  • Comparar erros absolutos entre grandezas de escalas diferentes.
  • Aumentar a precisão como primeira resposta, em vez de reformular.

Leituras recomendadas

  • Trefethen e Bau, lições 12 a 15 — condicionamento e estabilidade explicados com clareza excepcional.
  • Higham, Accuracy and Stability of Numerical Algorithms — a referência definitiva.
  • Documentação do numpy.linalg.cond e do scipy.linalg — diagnósticos disponíveis nas ferramentas.

Lloyd N. Trefethen and David Bau III (1997). Numerical Linear Algebra. SIAM. DOI: 10.1137/1.9780898719574. Nicholas J. Higham (2002). Accuracy and Stability of Numerical Algorithms. SIAM. DOI: 10.1137/1.9780898718027.

Referências

  1. Lloyd N. Trefethen; David Bau III (1997). Numerical Linear Algebra. SIAM.
  2. Nicholas J. Higham (2002). Accuracy and Stability of Numerical Algorithms. SIAM.