Lista 04 · Bisseção e falsa posição¶
Acompanha o capítulo 4. Todo problema aqui vira \(f(x) = 0\): a ressonância de um circuito, o atrito num cano de água, os juros de um financiamento. Comece sempre olhando o gráfico.
Como esta lista funciona
Abra o caderno no Colab, escreva a sua solução no lugar do # TODO e rode a
célula de teste logo abaixo. Ela mesma diz o que passou e o que falhou — você
não precisa esperar correção de ninguém.
O código de cada exercício também está aqui embaixo, caso você prefira colar num editor local. Os testes comparam números com tolerância.
Exercícios marcados com ✏️ são à mão, no papel, com 4 casas decimais — como na parte em papel das avaliações.
Exercício 01¶
✏️ À mão. Queremos \(\sqrt[3]{20}\), a raiz de \(f(x) = x^3 - 20\).
a) Mostre que existe uma raiz em \([2, 3]\).
b) Faça 4 iterações da bisseção, preenchendo a tabela (4 casas decimais):
| it | \(a\) | \(b\) | \(x_m\) | \(f(x_m)\) | novo intervalo |
|---|---|---|---|---|---|
| 1 | 2 | 3 | |||
| 2 | |||||
| 3 | |||||
| 4 |
c) Quantas iterações seriam necessárias para garantir erro menor que \(0{,}001\), partindo de \([2, 3]\)?
d) Faça uma iteração da falsa posição em \([2, 3]\). Ela chega mais perto de \(\sqrt[3]{20} = 2{,}7144\) do que a primeira iteração da bisseção?
Exercício 02¶
Escreva bissecao(f, a, b, tol, max_iter), que aplica a bisseção a f no
intervalo [a, b] e devolve o ponto médio da última iteração. Pare quando o erro
relativo aproximado (em %) ficar abaixo de tol, ou depois de max_iter
iterações.
def bissecao(f, a, b, tol, max_iter):
"""Raiz de f em [a, b] pela bisseção; para quando eps_a (%) < tol."""
xm = a
# TODO: laço até max_iter: guarda o anterior, ponto médio, teste de sinal
# para escolher a metade, e break quando eps_a < tol
return xm
# --- testes (não altere) ---
def g_ex02(x):
return x**2 - 2
def h_ex02(x):
return x**3 - 20
r = bissecao(g_ex02, 1, 2, 0.0001, 100)
assert abs(r - 1.41421356) < 1e-5, f"a raiz de x² - 2 é 1.41421... (veio {r})"
r = bissecao(h_ex02, 2, 3, 0.0001, 100)
assert abs(r - 2.71441762) < 1e-5, f"a raiz cúbica de 20 é 2.71442... (veio {r})"
r = bissecao(h_ex02, 2, 3, 0.0001, 1)
assert r == 2.5, "com max_iter = 1, só uma iteração: o ponto médio 2.5"
print("Exercício 02: todos os testes passaram!")
Exercício 03¶
Escreva iteracoes_necessarias(a, b, delta), que devolve o menor número de
iterações \(n\) da bisseção que garante \(\dfrac{b - a}{2^n} < \delta\).
Use um while: comece com a largura \(b - a\) e vá dividindo por 2, contando.
def iteracoes_necessarias(a, b, delta):
"""Menor n com (b - a) / 2**n < delta."""
n = 0
largura = b - a
# TODO: while a largura não ficar menor que delta: divide por 2 e conta
return n
# --- testes (não altere) ---
assert iteracoes_necessarias(2, 3, 0.001) == 10
assert iteracoes_necessarias(100, 200, 0.01) == 14
assert iteracoes_necessarias(0, 1, 0.6) == 1, "1/2 = 0.5 já é menor que 0.6"
assert iteracoes_necessarias(0, 8, 1) == 4, "8/2**3 = 1 NÃO é menor que 1"
print("Exercício 03: todos os testes passaram!")
Exercício 04¶
Escreva falsa_posicao(f, a, b, tol, max_iter), igual à bisseção do ex02, mas com
o ponto
Conte as iterações das duas em \(x^2 - 2\): qual precisou de menos?
def falsa_posicao(f, a, b, tol, max_iter):
"""Raiz de f em [a, b] pela falsa posição; para quando eps_a (%) < tol."""
xr = a
# TODO: o mesmo laço da bisseção, trocando o ponto médio por x_r
return xr
# --- testes (não altere) ---
def g_ex04(x):
return x**2 - 2
r = falsa_posicao(g_ex04, 1, 2, 0.0001, 100)
assert abs(r - 1.41421356) < 1e-5, f"veio {r}"
r = falsa_posicao(g_ex04, 1, 2, 0.0001, 1)
assert abs(r - 4 / 3) < 1e-12, "a primeira reta cruza o zero em 4/3"
print("Exercício 04: todos os testes passaram!")
Exercício 05¶
Eletrônica — ressonância. Num circuito com indutor \(L\) e capacitor \(C\) em série, a reatância (a "resistência" à corrente alternada) é
Na frequência de ressonância, \(X = 0\) e a corrente é máxima: é o princípio da
sintonia de um rádio. Escreva frequencia_ressonancia(L, C), que acha essa raiz
com a bissecao (já escrita) no intervalo de 100 Hz a 100 kHz, com tol = 1e-6
e max_iter = 200.
Confira com a fórmula \(f_0 = \dfrac{1}{2\pi\sqrt{LC}}\).
Dica: dentro da sua função, defina outra função reatancia(f) que usa o L e o
C recebidos, e passe-a para a bisseção.
import numpy as np
def bissecao(f, a, b, tol, max_iter):
"""Bisseção. JÁ ESCRITA."""
xm = a
for it in range(max_iter):
anterior = xm
xm = (a + b) / 2
if f(a) * f(xm) < 0:
b = xm
else:
a = xm
if abs((xm - anterior) / xm) * 100 < tol:
break
return xm
def frequencia_ressonancia(L, C):
"""Frequência (Hz) em que a reatância do circuito LC em série é zero."""
# TODO: defina reatancia(f) aqui dentro e chame bissecao(reatancia, 100, 100000, 1e-6, 200)
pass
# --- testes (não altere) ---
import numpy as np
f0 = frequencia_ressonancia(10e-3, 100e-9)
assert abs(f0 - 1 / (2 * np.pi * np.sqrt(10e-3 * 100e-9))) < 0.01, f"veio {f0}"
f0 = frequencia_ressonancia(1e-3, 4.7e-6)
assert abs(f0 - 1 / (2 * np.pi * np.sqrt(1e-3 * 4.7e-6))) < 0.01, "outro circuito"
print("Exercício 05: todos os testes passaram!")
Exercício 06¶
Hidráulica — o atrito num cano. O fator de atrito \(f\) de um cano (que decide a potência da bomba de uma adutora) obedece à equação de Colebrook:
em que \(\varepsilon/D\) é a rugosidade relativa do cano e \(Re\) é o número de
Reynolds do escoamento. Não dá para isolar \(f\). A função colebrook(f, ...)
(já escrita) calcula o lado esquerdo menos o direito: a raiz dela é o fator de
atrito.
Escreva fator_de_atrito(rugosidade, reynolds), que acha essa raiz com a
bissecao (já escrita) em \([0{,}008;\ 0{,}1]\).
import numpy as np
def bissecao(f, a, b, tol, max_iter):
"""Bisseção. JÁ ESCRITA."""
xm = a
for it in range(max_iter):
anterior = xm
xm = (a + b) / 2
if f(a) * f(xm) < 0:
b = xm
else:
a = xm
if abs((xm - anterior) / xm) * 100 < tol:
break
return xm
def colebrook(f, rugosidade, reynolds):
"""Lado esquerdo menos o direito da equação de Colebrook. JÁ ESCRITA."""
log10 = np.log(rugosidade / 3.7 + 2.51 / (reynolds * np.sqrt(f))) / np.log(10)
return 1 / np.sqrt(f) + 2 * log10
def fator_de_atrito(rugosidade, reynolds):
"""Fator de atrito de Darcy de um cano, pela equação de Colebrook."""
# TODO: defina g(f) que chama colebrook(f, rugosidade, reynolds) e use a bissecao
pass
# --- testes (não altere) ---
assert abs(fator_de_atrito(0.0001, 1e5) - 0.018513866104185588) < 1e-5
assert abs(fator_de_atrito(0.001, 1e6) - 0.019943465910851964) < 1e-5
print("Exercício 06: todos os testes passaram!")
Exercício 07¶
Finanças — os juros escondidos. Uma loja anuncia um carro de R$ 30 000 "em 36 parcelas de R$ 1 100". Numa prestação fixa (tabela Price), o valor à vista, a parcela \(P\), o número de parcelas \(n\) e a taxa mensal \(i\) se relacionam por
Escreva juros_mensais(valor, parcela, n), que acha \(i\) com a bissecao (já
escrita) entre \(0{,}0001\) e \(0{,}5\).
Quanto é isso ao ano? (Não é \(12 \times 1{,}585\,\%\).)
def bissecao(f, a, b, tol, max_iter):
"""Bisseção. JÁ ESCRITA."""
xm = a
for it in range(max_iter):
anterior = xm
xm = (a + b) / 2
if f(a) * f(xm) < 0:
b = xm
else:
a = xm
if abs((xm - anterior) / xm) * 100 < tol:
break
return xm
def juros_mensais(valor, parcela, n):
"""Taxa de juros mensal (fração) de um financiamento em n parcelas iguais."""
# TODO: defina diferenca(i) = valor - parcela * (1 - (1 + i)**(-n)) / i e use a bissecao
pass
# --- testes (não altere) ---
assert abs(juros_mensais(30000, 1100, 36) - 0.015850879862043078) < 1e-6
assert abs(juros_mensais(1000, 100, 12) - 0.029228540951898314) < 1e-6
print("Exercício 07: todos os testes passaram!")
Exercício 08¶
Várias raízes: a busca incremental. A bisseção precisa de um intervalo com uma troca de sinal. Quando a função tem várias raízes, o primeiro passo é procurá-las: dividir \([a, b]\) em \(n\) pedaços iguais e testar o sinal nas pontas de cada um.
Escreva intervalos_com_raiz(f, a, b, n), que devolve a lista de tuplas
(x_esq, x_dir) dos pedaços em que f troca de sinal.
import numpy as np
intervalos_com_raiz(np.sin, 0.5, 10, 100)
# -> três pedaços: um perto de pi, um de 2*pi e um de 3*pi
Depois de passar: o que acontece com n = 3? Por que a busca pode "pular" duas
raízes muito próximas?
def intervalos_com_raiz(f, a, b, n):
"""Divide [a, b] em n pedaços iguais e devolve a lista dos pedaços
(x_esq, x_dir) em que f troca de sinal."""
largura = (b - a) / n
achados = []
# TODO: para cada pedaço k, calcule as pontas e teste f(esq) * f(dir) < 0
return achados
# --- testes (não altere) ---
import numpy as np
r = intervalos_com_raiz(np.sin, 0.5, 10, 100)
assert len(r) == 3, f"sen(x) tem 3 raízes entre 0.5 e 10 (veio {len(r)})"
for k in range(3):
esq, dir = r[k]
assert esq < (k + 1) * np.pi < dir, f"o pedaço {k} devia conter {k + 1}*pi"
assert intervalos_com_raiz(np.sin, 0.5, 3, 10) == [], "sen não troca de sinal entre 0.5 e 3"
print("Exercício 08: todos os testes passaram!")