Bisseção e Taxa de Convergência
Objetivos de Aprendizagem
- Enunciar a garantia de confinamento da bisseção com suas hipóteses, e dizer o que ela não promete.
- Calcular a contagem exata de iterações para uma tolerância, distinguir iterações de avaliações de função e conferir a contagem com
scipy.optimize.bisect. - Medir a convergência da bisseção e explicar por que a largura do intervalo cai exatamente à metade enquanto o erro não cai.
- Escolher entre os testes de parada por largura, largura relativa, resíduo e limite de iterações, e dizer o que cada um certifica.
- Prever a precisão atingível a partir do condicionamento, e reconhecer onde o arredondamento encerra a convergência.
Contexto e Motivação
guess-and-check-and-bisection-search constrói o laço, e continuity-and-the-intermediate-value-theorem explica por que há uma raiz dentro do intervalo, mostra uma troca de sinal num polo e acompanha como os doubles se esgotam. Nenhuma delas responde às perguntas que um engenheiro faz a um método numérico. Quantas iterações custa uma tolerância, exatamente? O que o teste de parada certifica de verdade? Qual a precisão possível, dado o condicionamento de conditioning-and-numerical-stability?
O exemplo condutor é a taxa interna de retorno (TIR), a função das planilhas que leva esse nome. Fluxos de caixa nos anos têm valor presente líquido , e a TIR é uma raiz dele. Em geral não há forma fechada. A bisseção é lenta, mas pede apenas uma troca de sinal, e é por isso que solvers como o de Brent a mantêm como rede de segurança.
Teoria Central
O método e sua garantia
Hipóteses. é contínua em , e e são não nulos e têm sinais opostos.
Método. Faça . Para , seja o ponto médio de . Se , pare. Caso contrário, é a metade cujos extremos têm sinais opostos.
Conclusão. O Teorema do Valor Intermediário coloca uma raiz em cada intervalo. Os intervalos encaixados encolhem até um único ponto , e a continuidade força . Para todo ,
Cada iteração custa uma avaliação de e não precisa de derivada. A garantia não diz que a raiz é única, nem qual raiz será encontrada.
Contando iterações
A largura do intervalo atinge uma tolerância no menor com :
Essa contagem é incomum entre métodos numéricos: não depende de , a não ser que um acerto exato encerre a execução mais cedo. As avaliações de função somam , porque os dois extremos são testados antes. Cada dígito decimal custa iterações.
Convergência linear, dita com cuidado
Uma sequência com erros converge linearmente com taxa quando tende a . A cota satisfaz exatamente. O erro verdadeiro em geral não satisfaz, porque um ponto médio pode cair perto de por sorte e o seguinte, mais longe. Assim, a taxa descreve a cota que domina o erro, um dígito binário por iteração em média, e não uma razão observada a cada passo. secant-method-and-order-of-convergence formaliza a ordem de convergência.
Critérios de parada
| Teste | Certifica | Fraqueza |
|---|---|---|
| Largura: | a menos de , se os sinais estão certos | Diz pouco se é bem menor que ; pode nunca terminar se está abaixo do espaçamento dos floats em |
| Largura relativa: | Dígitos de | Não pode ser satisfeito quando |
| Resíduo: | é raiz exata de | Depende das unidades de |
| Limite de iterações | O laço termina | Nada sobre a precisão |
Código real combina esses testes. scipy.optimize.bisect recebe xtol, rtol e maxiter, com padrões , e , e documenta que o resultado satisfaz np.isclose(x, x0, atol=xtol, rtol=rtol). Seu xtol padrão é um teste absoluto: em sobre ele informa sucesso em , um erro relativo de 82 por cento, enquanto xtol=1e-20 dá em 67 iterações.
Resíduo, largura e condicionamento
A largura limita o erro direto. O resíduo é o erro reverso: resolve exatamente . Para uma raiz simples ( com contínua por perto), a expansão de primeira ordem liga os dois, , então é o número de condição absoluto da raiz.
Isso também fixa o piso de precisão. Se os valores calculados de têm ruído de tamanho , os sinais só merecem confiança onde , então perto de uma raiz simples a zona de dúvida tem meia-largura em torno de . Dentro dela, o intervalo continua caindo à metade em volta de uma troca de sinal calculada, e sua largura deixa de medir o erro.
Exemplos Resolvidos
Exemplo 1: uma TIR com tolerância
Tome os fluxos de caixa . O é contínuo em , com e . Substituir dá uma cúbica com uma única troca de sinal nos coeficientes, então pela regra de Descartes há exatamente uma raiz com : . Para , . A execução, com a cota ao lado do erro verdadeiro:
textn m_n f(m_n) e_n 2^-n e_n/e_(n-1) 1 0.5 -4.12e+02 3.37e-01 5.00e-01 2 0.25 -1.43e+02 8.66e-02 2.50e-01 0.26 3 0.125 +7.61e+01 3.84e-02 1.25e-01 0.44 4 0.1875 -4.35e+01 2.41e-02 6.25e-02 0.63 5 0.15625 +1.35e+01 7.16e-03 3.13e-02 0.30 6 0.171875 -1.56e+01 8.47e-03 1.56e-02 1.18 7 0.1640625 -1.23e+00 6.57e-04 7.81e-03 0.08 8 0.16015625 +6.10e+00 3.25e-03 3.91e-03 4.95 ... 26 0.16340561 -2.13e-05 1.14e-08 1.49e-08 0.43 27 0.16340560 -7.42e-06 3.97e-09 7.45e-09 0.35
A cota vale em toda linha. O erro sobe em 7 das 26 transições, e mesmo assim a inclinação ajustada de contra é e a média geométrica das razões é . O método gastou 29 avaliações. scipy.optimize.bisect(npv, 0, 1, xtol=1e-8) informa 27 iterações e 29 chamadas de função e devolve o mesmo . Com o mesmo xtol, scipy.optimize.brentq usa 9 chamadas e cai a de .
Exemplo 2: o teste de resíduo depende das unidades
Expresse os mesmos fluxos de caixa em escalas diferentes e pare em ou em largura :
textescala dos fluxos iterações, teste de resíduo erro em r iterações, teste de largura 0.001 7 6.57e-04 27 1 16 7.71e-07 27 1000 24 3.48e-09 27 1000000 36 1.15e-12 27
A mesma taxa de retorno, o mesmo teste, e um erro que muda em oito ordens de grandeza. O teste de largura nem nota a escala. Na escala , , e o resíduo de parada prevê um erro de , como na tabela. Um teste de resíduo é o certo quando tem significado próprio, como em "as contas fecham a menos de ", e é o errado como substituto para dígitos de .
Exemplo 3: onde a convergência para
Rode a TIR até o fim dos floats, parando quando o ponto médio coincide com um extremo:
textformato divisões largura final erro verdadeiro float64 55 2.8e-17 5.4e-17 float32 26 1.5e-08 3.5e-09
A contagem é 55 e não 53, como acontece com a raiz perto de em continuity-and-the-intermediate-value-theorem, porque perto de o espaçamento do double é . Em geral a contagem fica em torno de . Em float64 o erro verdadeiro é o dobro da largura final, então está fora do último intervalo. É o piso de ruído em ação: nos 801 doubles consecutivos centrados em o VPL calculado erra até , o que dividido por dá uma zona de , alguns espaçamentos de float, e dentro dela os sinais calculados podem estar errados. Esses resultados dependem de como o VPL é escrito. A tabela o avalia termo a termo, e em float64 a regra de Horner em acerta um 0.0 exato depois de 46 iterações, com erro .
Agora tome uma raiz mal condicionada. tem , e sua forma expandida é avaliada pela regra de Horner:
textintervalo pontos médios largura final resultado erro verdadeiro [0.8, 1.1] 7 4.7e-03 0.99453125 5.5e-03 [0.9, 1.4] 15 3.1e-05 0.99248352 7.5e-03 [0.7, 1.2] 21 4.8e-07 0.99500604 5.0e-03 [0.95, 1.02] 47 1.1e-15 1.00734781 7.3e-03
Toda execução para porque Horner devolve exatamente 0.0, uma coincidência de arredondamento e não uma raiz. Esse último ponto médio encerra a execução antes de o intervalo cair à metade, então pontos médios deixam uma largura de cerca de . A última linha informa uma largura perto de com um erro mais de vezes maior. Numa grade de 600.001 pontos em o sinal calculado troca 73.860 vezes, entre e . Nos 100.000 pontos da grade com o maior calculado é , tudo ruído, já que o valor verdadeiro ali fica abaixo de . E atinge esse valor em , que é a zona prevista. scipy.optimize.bisect e brentq no último intervalo devolvem e , então um solver melhor não ajuda. A bisseção na forma fatorada (x - 1)**7 devolve exatamente nos quatro intervalos: o problema estava na representação de .
Exemplo 4: hipóteses que faltam
Duas raízes, nenhuma troca de sinal. Os fluxos têm TIRs de 10 e 20 por cento, mas e . scipy.optimize.bisect levanta ValueError em . Em e ele encontra cada raiz. Uma troca de sinal é suficiente para haver raiz, não necessária, e um número par de raízes se esconde dela.
Um polo. scipy.optimize.bisect(math.tan, 1, 2) informa convergência depois de 39 iterações em , onde vale . A continuidade falha, como para em continuity-and-the-intermediate-value-theorem, e o teste de largura não consegue ver isso. Uma conferência de no final consegue.
Equívocos Comuns e Armadilhas
- "Convergência linear quer dizer que o erro cai à metade a cada passo." A cota cai. No Exemplo 1 o erro chegou a crescer por um fator de , entre e .
- "Testar
f(a) * f(m) < 0é o mesmo que comparar sinais." Com o produto sofre underflow para-0.0, o teste é sempre falso e o laço converge para . Comparar os sinais diretamente dá . - "
(a + b) / 2é sempre seguro." Ele estoura quando e são enormes e têm o mesmo sinal:1.6e308 + 1.7e308dáinf.a + (b - a) / 2conserta esse caso e falha no oposto: coma = -1.7e308eb = 1.7e308,b - aestoura e o resultado éinf, enquanto(a + b) / 2dá0.0. Um intervalo que atravessa o zero é o caso normal para uma raiz perto de , então nenhuma das duas escritas é segura para todo intervalo nessa escala.a / 2 + b / 2resolve os dois casos, ao custo de arredondamento quando os extremos são subnormais. - "Largura abaixo da tolerância quer dizer que a resposta é boa assim." Só se os sinais calculados estiverem certos, e o Exemplo 3 mostra que isso pode falhar.
- "Um teste relativo serve para qualquer raiz." Só com um teste relativo, em não tem saída até os floats acabarem, depois de 1076 iterações que descem pelos subnormais até
5e-324. Uma raiz em precisa de um piso absoluto. - "A bisseção está obsoleta." A documentação do SciPy considera
brentqem geral a melhor de suas rotinas de busca de raízes, e o descreve como uma combinação de confinamento, bisseção e interpolação quadrática inversa. A bisseção sobrevive dentro dele, e a bisseção pura continua sendo um método cujo custo pode ser dito antes de rodar.
Resumo
Para contínua com troca de sinal em , a bisseção mantém uma raiz num intervalo de largura , com uma avaliação por iteração, e precisa de iterações para a largura , seja qual for . A taxa é da cota: o erro verdadeiro pode subir de um passo para o outro e ainda assim render um bit por iteração em média. A largura controla o erro direto, o resíduo controla o erro reverso, e liga os dois perto de uma raiz simples. Testes absolutos falham para raízes minúsculas, testes relativos falham em zero, testes de resíduo dependem das unidades e um limite de iterações só encerra o laço. O arredondamento encerra a convergência perto do espaçamento dos floats numa raiz bem condicionada, e muito antes numa raiz mal condicionada, onde a largura do intervalo deixa de medir o erro.
Documentation Links
- SciPy documentation: scipy.optimize.bisect
- SciPy documentation: scipy.optimize.brentq
- Driscoll and Braun: Fundamentals of Numerical Computation, 4.1 The rootfinding problem
- MIT OpenCourseWare 18.330 (2012): Lecture Notes: Nonlinear Equations
- Goldberg (1991): What Every Computer Scientist Should Know About Floating-Point Arithmetic