Pular para conteúdo

Lista 02 · Diferenças finitas

Acompanha o capítulo 2. O primeiro exercício é à mão, como a parte em papel da prova. Os outros pedem funções curtas: cada uma é a fórmula do quadro, escrita em Python.

Abrir no Colab

Baixar o caderno

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. Seja \(f(x) = 2x^2 - 5x + 1\). Com \(h = 0{,}5\), calcule uma aproximação de \(f'(2)\) pelas diferenças

a) progressiva; b) regressiva; c) central.

d) Derive \(f\) à mão e calcule o erro relativo percentual de cada aproximação.

e) Uma das três acertou em cheio. Use a dedução por Taylor para explicar por quê — a resposta não é "sorte".

Exercício 02

Escreva central(f, x, h), que devolve a aproximação de \(f'(x)\) pela diferença central:

\[ f'(x) \approx \frac{f(x+h) - f(x-h)}{2h} \]

f é uma função (o nome dela, sem parênteses).

def g(x):
    return x**3

central(g, 2, 0.1)    # -> 12.01   (a exata é 12)
def central(f, x, h):
    """Derivada de f em x pela diferença central, com passo h."""
    # TODO: a fórmula tem f(x + h), f(x - h) e 2 * h entre parênteses
    pass


# --- testes (não altere) ---
def cubo_ex02(x):
    return x**3


def reta_ex02(x):
    return 7 * x - 2


assert abs(central(cubo_ex02, 2, 0.1) - 12.01) < 1e-9, "x**3 em x = 2 com h = 0.1"
assert abs(central(reta_ex02, 5, 0.3) - 7) < 1e-9, "a derivada de uma reta é a inclinação"
assert abs(central(cubo_ex02, -1, 0.01) - 3.0001) < 1e-9, "x**3 em x = -1"
print("Exercício 02: todos os testes passaram!")

Exercício 03

Escreva erro_relativo(aprox, exato), que devolve o erro relativo percentual \(\left|\dfrac{\text{aprox} - \text{exato}}{\text{exato}}\right| \times 100\).

erro_relativo(4, 3)       # -> 33.333...
erro_relativo(2.9, 3)     # -> 3.333...
def erro_relativo(aprox, exato):
    """Erro relativo percentual entre a aproximação e o valor exato."""
    # TODO: use abs(...) e não esqueça o * 100
    pass


# --- testes (não altere) ---
assert abs(erro_relativo(4, 3) - 100 / 3) < 1e-9
assert abs(erro_relativo(2.9, 3) - 10 / 3) < 1e-9, "o erro é sempre positivo"
assert abs(erro_relativo(-0.5, -0.4) - 25) < 1e-9, "exato negativo: o erro continua positivo"
assert erro_relativo(7, 7) == 0
print("Exercício 03: todos os testes passaram!")

Exercício 04

Farmacologia. Depois de um comprimido, a concentração do remédio no sangue (em mg/L) segue, \(t\) horas depois,

\[ C(t) = 20\,\big(e^{-0{,}2t} - e^{-1{,}5t}\big). \]

Ela sobe enquanto o remédio é absorvido e desce enquanto o corpo o elimina. Escreva taxa_concentracao(t, h), que devolve a taxa de variação de \(C\) (mg/L por hora) no instante t, pela diferença central com passo h.

taxa_concentracao(1, 0.01)    # -> ≈ 3.419  (subindo)
taxa_concentracao(5, 0.01)    # -> ≈ -1.455 (descendo)

Em que instante, aproximadamente, a taxa passa de positiva para negativa? O que isso significa para o paciente? (Guarde a resposta: é o problema de raiz da Unidade 3.)

import numpy as np


def C(t):
    """Concentração (mg/L) t horas depois do comprimido. JÁ ESCRITA."""
    return 20 * (np.exp(-0.2 * t) - np.exp(-1.5 * t))


def taxa_concentracao(t, h):
    """Taxa de variação de C em t (mg/L por hora), pela central."""
    # TODO: a mesma fórmula do ex02, com C no lugar de f
    pass


# --- testes (não altere) ---
import numpy as np



def exata_ex04(t):
    return 20 * (-0.2 * np.exp(-0.2 * t) + 1.5 * np.exp(-1.5 * t))


assert abs(taxa_concentracao(1, 0.01) - exata_ex04(1)) < 1e-3, "em t = 1 h a concentração sobe"
assert abs(taxa_concentracao(5, 0.01) - exata_ex04(5)) < 1e-3, "em t = 5 h ela desce"
assert taxa_concentracao(1, 0.01) > 0 and taxa_concentracao(5, 0.01) < 0
print("Exercício 04: todos os testes passaram!")

Exercício 05

Escreva segunda_central(f, x, h), que aproxima \(f''(x)\) por

\[ f''(x) \approx \frac{f(x+h) - 2f(x) + f(x-h)}{h^2}. \]

Aplicação — física. A posição de um carro num teste de frenagem é \(s(t) = 30t - 2{,}5t^2\) metros. A aceleração é \(s''(t)\). Quanto ela vale? Por que a fórmula acerta exatamente, qualquer que seja \(h\)?

def segunda_central(f, x, h):
    """Segunda derivada de f em x, com passo h (pesos 1, -2, 1)."""
    # TODO: o denominador é h ao quadrado
    pass


# --- testes (não altere) ---
import numpy as np



def posicao_ex05(t):
    return 30 * t - 2.5 * t**2


assert abs(segunda_central(posicao_ex05, 3, 0.5) - (-5)) < 1e-9, "a aceleração do carro é -5 m/s²"
assert abs(segunda_central(np.sin, 1.0, 0.001) - (-np.sin(1.0))) < 1e-5, "a segunda derivada de sen é -sen"
assert abs(segunda_central(np.exp, 0.0, 0.01) - 1) < 1e-4
print("Exercício 05: todos os testes passaram!")

Exercício 06

Veja a ordem com os próprios olhos. Escreva razao_dos_erros(f, derivada_exata, x, h), que calcula o erro absoluto da diferença central com passo h e com passo h / 2, e devolve a razão erro(h) / erro(h/2).

A dedução por Taylor promete que a central é \(O(h^2)\). Que número a razão deve dar? Teste com \(e^x\) em \(x = 0\) e \(h = 0{,}1\).

def central(f, x, h):
    """Diferença central. JÁ ESCRITA."""
    return (f(x + h) - f(x - h)) / (2 * h)


def razao_dos_erros(f, derivada_exata, x, h):
    """Erro da central com h dividido pelo erro com h/2."""
    # TODO: dois erros absolutos (abs), depois a divisão de um pelo outro
    pass


# --- testes (não altere) ---
import numpy as np


r = razao_dos_erros(np.exp, np.exp(0.0), 0.0, 0.1)
assert abs(r - 4) < 0.01, f"a central é O(h²): h pela metade, erro 4 vezes menor (deu {r})"
r = razao_dos_erros(np.sin, np.cos(1.0), 1.0, 0.05)
assert abs(r - 4) < 0.01
print("Exercício 06: todos os testes passaram!")

Exercício 07

O melhor \(h\). Escreva melhor_h(f, derivada_exata, x), que testa a diferença central com \(h = 10^{-1}, 10^{-2}, \ldots, 10^{-15}\) e devolve o \(h\) que deu o menor erro absoluto.

Use o padrão "extremo": comece com o primeiro \(h\) como candidato e troque sempre que achar um erro menor.

Teste com \(f(x) = x^3\) em \(x = 1\) (a derivada exata é 3). O melhor \(h\) é \(10^{-15}\)? Por quê?

def central(f, x, h):
    """Diferença central. JÁ ESCRITA."""
    return (f(x + h) - f(x - h)) / (2 * h)


def melhor_h(f, derivada_exata, x):
    """O h, entre 1e-1 e 1e-15, com o menor erro da central."""
    # TODO: laço com k de 1 a 15, h = 10.0**(-k); guarde o melhor h e o menor erro
    pass


# --- testes (não altere) ---
def cubo_ex07(x):
    return x**3


h = melhor_h(cubo_ex07, 3.0, 1.0)
assert h is not None, "faltou o return?"
assert 1e-7 <= h <= 1e-4, f"o melhor h fica no fundo do V, longe das pontas (deu {h})"
assert h == 1e-05 or h == 1e-06, f"deu {h}"
print("Exercício 07: todos os testes passaram!")

Exercício 08

Economia — vale a pena a encomenda extra? Uma padaria industrial tem custo diário \(C(q) = 800 + 1{,}2q + 0{,}0004q^2\) reais para produzir \(q\) pães. Um cliente oferece comprar pães extras por um preço fixo. Vale a pena aceitar se o preço for maior que o custo marginal \(C'(q)\) na produção atual.

Escreva vale_a_pena(preco, q), que devolve True ou False. As funções custo e central já estão escritas: o trabalho é compô-las. Use \(h = 1\) (um pão).

vale_a_pena(2.00, 500)     # -> True   (custo marginal: R$ 1,60)
vale_a_pena(2.00, 1500)    # -> False  (custo marginal: R$ 2,40)
def custo(q):
    """Custo diário (R$) para produzir q pães. JÁ ESCRITA."""
    return 800 + 1.2 * q + 0.0004 * q**2


def central(f, x, h):
    """Diferença central. JÁ ESCRITA."""
    return (f(x + h) - f(x - h)) / (2 * h)


def vale_a_pena(preco, q):
    """True se o preço oferecido supera o custo marginal em q."""
    # TODO: custo marginal = central(custo, q, 1); compare com o preço
    pass


# --- testes (não altere) ---
assert vale_a_pena(2.00, 500) is True, "em 500 pães o custo marginal é R$ 1,60"
assert vale_a_pena(2.00, 1500) is False, "em 1500 pães o custo marginal é R$ 2,40"
assert vale_a_pena(1.61, 500) is True
assert vale_a_pena(1.59, 500) is False
print("Exercício 08: todos os testes passaram!")