from math import factorial, isclose
import sympy as sp
import numpy as np
def _validate_interpolation_inputs(x, y, xp=None):
"""Valida entradas para funções de interpolação.
Esta função realiza validações abrangentes dos dados de entrada para garantir
que a interpolação possa ser realizada corretamente.
Parameters
----------
x, y : array_like
Nós e valores correspondentes. Devem ser sequências de números reais.
xp : float, optional
Ponto de interpolação. Deve estar dentro do intervalo dos nós x para
melhores resultados, embora extrapolações sejam permitidas.
Returns
-------
x_valid, y_valid : np.ndarray
Entradas validadas e convertidas para arrays NumPy de ponto flutuante.
Raises
------
ValueError
Se as entradas não forem válidas (dimensões incorretas, comprimentos
diferentes, pontos x duplicados, etc.).
TypeError
Se os dados não puderem ser convertidos para números reais.
"""
# Validação de tipo e conversão
try:
x = np.asarray(x, dtype=float)
y = np.asarray(y, dtype=float)
except (ValueError, TypeError) as e:
raise TypeError(f"Os dados de entrada devem ser numéricos. Erro: {e}")
# Validação de dimensionalidade
if x.ndim != 1:
raise ValueError(f"x deve ser um array 1D. Recebido: {x.ndim}D com shape {x.shape}")
if y.ndim != 1:
raise ValueError(f"y deve ser um array 1D. Recebido: {y.ndim}D com shape {y.shape}")
# Validação de comprimento
if len(x) != len(y):
raise ValueError(f"x e y devem ter o mesmo comprimento. x: {len(x)}, y: {len(y)}")
if len(x) < 2:
raise ValueError(f"São necessários pelo menos 2 pontos para interpolação. Recebidos: {len(x)}")
# Validação de pontos x únicos
unique_x = np.unique(x)
if len(unique_x) != len(x):
duplicates = x[np.where(np.diff(np.sort(x)) == 0)[0]]
raise ValueError(f"Os pontos x devem ser únicos. Pontos duplicados encontrados: {duplicates}")
# Validação de valores finitos (não NaN ou infinito)
if not np.all(np.isfinite(x)):
raise ValueError("Todos os valores em x devem ser finitos (não NaN ou infinito)")
if not np.all(np.isfinite(y)):
raise ValueError("Todos os valores em y devem ser finitos (não NaN ou infinito)")
# Validação opcional do ponto de interpolação
if xp is not None:
try:
xp = float(xp)
except (ValueError, TypeError):
raise TypeError(f"O ponto de interpolação xp deve ser um número. Recebido: {type(xp)}")
return x, y
def _validate_max_grau(n, max_grau):
"""Valida e ajusta o grau máximo para interpolação polinomial.
Esta função garante que o grau do polinômio interpolador seja válido
dado o número de pontos disponíveis. O grau máximo possível é n-1,
onde n é o número de pontos.
Parameters
----------
n : int
Número de pontos de dados disponíveis. Deve ser >= 2.
max_grau : int or None
Grau máximo solicitado. Se None, usa o máximo possível (n-1).
Deve ser um inteiro não-negativo.
Returns
-------
int
Grau máximo válido para interpolação. Sempre estará no intervalo [1, n-1].
Raises
------
TypeError
Se max_grau não for None, int ou conversível para int.
ValueError
Se n for menor que 2 ou max_grau for negativo.
"""
# Validação do número de pontos
if not isinstance(n, int) or n < 2:
raise ValueError(f"Número de pontos deve ser um inteiro >= 2. Recebido: {n}")
# Caso padrão: usar grau máximo possível
if max_grau is None:
return n - 1
# Validação e conversão do tipo
try:
max_grau = int(max_grau)
except (ValueError, TypeError):
raise TypeError(f"max_grau deve ser um inteiro ou None. Recebido: {type(max_grau)}")
# Validação do valor
if max_grau < 0:
raise ValueError(f"max_grau deve ser não-negativo. Recebido: {max_grau}")
# Ajuste automático se fora do limite
if max_grau > n - 1:
return n - 1
elif max_grau < 1:
return 1
return max_grau
[documentos]
def dados_interpolacao():
"""Lê interativamente pontos para interpolação com validação robusta.
Esta função solicita ao usuário os dados necessários para interpolação:
número de pontos, coordenadas x e y, e ponto de interpolação.
Inclui validações para garantir que os dados sejam adequados.
Returns
-------
tuple
Tupla (x_vals, y_vals, x_interp) onde:
- x_vals: list of float, coordenadas x dos pontos
- y_vals: list of float, coordenadas y dos pontos
- x_interp: float, ponto onde avaliar a interpolação
Raises
------
ValueError
Se os dados inseridos forem inválidos.
KeyboardInterrupt
Se o usuário interromper a entrada (Ctrl+C).
"""
try:
# Leitura e validação do número de pontos
while True:
try:
n_str = input("\nDigite o número de pontos (n >= 2): ").strip()
n = int(n_str)
if n < 2:
print("Erro: São necessários pelo menos 2 pontos. Tente novamente.")
continue
if n > 100: # Limite razoável para evitar entrada excessiva
print("Erro: Número máximo de pontos é 100. Tente novamente.")
continue
break
except ValueError:
print("Erro: Digite um número inteiro válido. Tente novamente.")
x_vals = []
y_vals = []
# Leitura dos pontos com validação
print(f"\nDigite as coordenadas para {n} pontos:")
for i in range(n):
while True:
try:
x_str = input(f"x[{i}] = ").strip()
x = float(x_str)
y_str = input(f"y[{i}] = ").strip()
y = float(y_str)
# Verificação de valores finitos
if not (np.isfinite(x) and np.isfinite(y)):
print("Erro: Valores devem ser finitos (não NaN ou infinito). Tente novamente.")
continue
x_vals.append(x)
y_vals.append(y)
break
except ValueError:
print("Erro: Digite números válidos. Tente novamente.")
# Validação adicional: pontos x únicos
if len(set(x_vals)) != len(x_vals):
print("Aviso: Alguns pontos x são duplicados. A interpolação pode não funcionar corretamente.")
# Leitura do ponto de interpolação
while True:
try:
x_interp_str = input("Digite o valor de x para interpolar: ").strip()
x_interp = float(x_interp_str)
if not np.isfinite(x_interp):
print("Erro: O ponto de interpolação deve ser finito. Tente novamente.")
continue
break
except ValueError:
print("Erro: Digite um número válido. Tente novamente.")
return x_vals, y_vals, x_interp
except KeyboardInterrupt:
print("\n\nEntrada interrompida pelo usuário.")
raise
except Exception as e:
print(f"\nErro inesperado na leitura dos dados: {e}")
raise
[documentos]
def obter_max_grau(n):
"""Solicita ao usuário o grau máximo para interpolação.
Parameters
----------
n : int
Número de pontos disponíveis.
Returns
-------
int or None
Grau máximo escolhido ou ``None`` para usar o máximo disponível.
"""
try:
val = input(f"Digite o grau máximo desejado (máximo {n-1}), ou deixe vazio para usar o máximo: ")
if val.strip() == '':
return None
grau = int(val)
if grau < 1 or grau > n - 1:
print("Após limite, usando o máximo possível.")
return None
return grau
except:
print("Entrada inválida, usando o máximo possível.")
return None
[documentos]
def tabela_diferencas_divididas(x, y):
"""Calcula a tabela de diferenças divididas (Newton).
Parameters
----------
x, y : sequence of float
Nós e valores correspondentes.
Returns
-------
list of lists
Tabela em que cada linha j contém as diferenças divididas de ordem j.
"""
x, y = _validate_interpolation_inputs(x, y)
n = len(x)
tabela = [y.copy()]
for j in range(1, n):
coluna = []
for i in range(n - j):
numerador = tabela[j - 1][i + 1] - tabela[j - 1][i]
denominador = x[i + j] - x[i]
coluna.append(numerador / denominador)
tabela.append(coluna)
return tabela
# impressao de tabela
[documentos]
def imprimir_tabela_diferencas_divididas(tabela, verbose=True):
if not verbose:
return
print("\nTabela de Diferenças Divididas:")
for i in range(len(tabela[0])):
linha = [f"{tabela[j][i]:>12.6f}" if i < len(tabela[j]) else " " * 12 for j in range(len(tabela))]
print(" ".join(linha))
[documentos]
def tabela_diferencas_finitas(y):
"""Calcula tabela de diferenças finitas progressivas.
Parameters
----------
y : sequence of float
Valores y nos nós igualmente espaçados.
Returns
-------
list of lists
Tabela de diferenças finitas progressivas.
"""
y = np.asarray(y, dtype=float)
if y.ndim != 1:
raise ValueError("y deve ser um array 1D.")
if len(y) < 2:
raise ValueError("São necessários pelo menos 2 pontos para diferenças finitas.")
n = len(y)
tabela = [y.copy()]
for j in range(1, n):
coluna = []
for i in range(n - j):
coluna.append(tabela[j-1][i+1] - tabela[j-1][i])
tabela.append(coluna)
return tabela
[documentos]
def imprimir_tabela_diferencas_finitas(tabela, verbose=True):
if not verbose:
return
print("\nTabela de Diferenças Finitas Progressivas:")
for i in range(len(tabela[0])):
linha = [f"{tabela[j][i]:>12.6f}" if i < len(tabela[j]) else " " * 12 for j in range(len(tabela))]
print(" ".join(linha))
[documentos]
def perguntar_erro(x_vals, x_interp, grau, valor_interpolado):
resposta = input("Deseja calcular erro truncamento e erro real? (s/n) ").strip().lower()
if resposta == 's':
func_str = input("Digite a função f(x) em Python (ex: exp(x)): ").strip()
return calcular_erro(func_str, x_vals, x_interp, grau, valor_interpolado)
else:
print("Cálculo de erro não realizado.")
return None, None
[documentos]
def calcular_erro(func_str, x_vals, x_interp, grau, valor_interpolado):
"""Calcula estimativa do erro de truncamento do polinômio interpolador.
Parameters
----------
func_str : str
Expressão simbólica de f(x).
x_vals : sequence
Nós usados na interpolação.
x_interp : float
Ponto em que a interpolação foi avaliada.
grau : int
Grau do polinômio usado.
valor_interpolado : float
Valor interpolado (não usado diretamente no cálculo aqui).
Returns
-------
(float, None)
Erro de truncamento máximo estimado e None (placeholder para erro real).
"""
x = sp.Symbol('x')
f = sp.sympify(func_str)
try:
# derivada de ordem n+1 para estimar erro máximo (limitante superior)
f_deriv = f.diff(x, grau + 1)
# determina o ponto de máximo do valor da derivada no intervalo (aproximação)
x_max = max(x_vals)
f_deriv_max = abs(f_deriv.evalf(subs={x: x_max}))
# produtorio dos termos (x - xi)
produto = 1.0
for xi in x_vals:
produto *= (x_interp - xi)
# erro de truncamento máximo
erro_trunc_max = (f_deriv_max / factorial(grau + 1)) * abs(produto)
# Exibe informações e valores
# print(f"\nFunção: {func_str}")
# print(f"Derivada de ordem {grau+1} máxima em x = {x_max}: {f_deriv_max}")
#print(f"Produto dos termos (x_interp - xi): {produto}")
print(f"Erro de truncamento máximo): {erro_trunc_max}") # deixar so o erro truncamento, q é o ideal é necessário (prática 21/10)
return erro_trunc_max, None
except Exception as e:
print(f"Erro ao calcular erro truncamento máximo: {e}")
return None, None
[documentos]
def newton_dif_divididas(x, tabela_diferencas, xp, max_grau=None, verbose=False, tabela=None, grafico=None):
"""Avalia o polinômio interpolador de Newton usando diferenças divididas.
Esta função implementa o método de interpolação polinomial de Newton baseado
em diferenças divididas, que é numericamente mais estável que o método de
Lagrange para avaliação em múltiplos pontos.
Parameters
----------
x : array_like
Nós (pontos x) onde os valores são conhecidos. Devem ser números reais
únicos e finitos.
tabela_diferencas : list of lists
Tabela de diferenças divididas calculada previamente (como retornada
por tabela_diferencas_divididas). Cada linha j contém as diferenças
divididas de ordem j.
xp : float
Ponto onde avaliar o polinômio interpolador. Deve ser um número finito.
max_grau : int or None, optional
Grau máximo do polinômio interpolador. Se None (padrão), usa o grau
máximo possível (n-1, onde n é o número de pontos). Deve estar no
intervalo [1, n-1].
verbose : bool, optional
Se True, imprime os cálculos detalhados do processo de interpolação.
Se False (padrão), executa silenciosamente.
tabela : bool or None, optional
Se True, mostra a tabela de diferenças divididas utilizada.
Se None (padrão), usa o valor da variável global 'tabela' ou False.
grafico : bool or None, optional
Se True, gera um gráfico mostrando os pontos originais, a curva
interpolada e o ponto de interpolação. Se None (padrão), usa o valor
da variável global 'grafico' ou False. Requer matplotlib instalado.
Returns
-------
float
Valor interpolado do polinômio de Newton no ponto xp.
Raises
------
ValueError
Se as entradas não forem válidas ou se a tabela de diferenças não
for consistente com os pontos x.
TypeError
Se os tipos de entrada não forem adequados.
RuntimeError
Se ocorrer erro na avaliação do polinômio.
Notes
-----
O método de Newton com diferenças divididas é definido pela fórmula:
.. math::
P_n(x) = f[x_0] + f[x_0,x_1](x-x_0) + f[x_0,x_1,x_2](x-x_0)(x-x_1) + \\cdots
onde :math:`f[x_0,x_1,\\dots,x_k]` são as diferenças divididas de ordem k.
A complexidade computacional é O(n) para avaliação em um ponto, após
a pré-computação da tabela de diferenças divididas O(n²).
Examples
--------
>>> x = [0, 1, 2]
>>> y = [0, 1, 4]
>>> tabela = tabela_diferencas_divididas(x, y)
>>> newton_dif_divididas(x, tabela, 1.5)
2.25
>>> # Interpolação quadrática
>>> newton_dif_divididas(x, tabela, 1.5, max_grau=2)
2.25
"""
# Validações de entrada
x = np.asarray(x, dtype=float)
if x.ndim != 1:
raise ValueError(f"x deve ser um array 1D. Recebido: {x.ndim}D")
n = len(x)
if n < 2:
raise ValueError(f"São necessários pelo menos 2 pontos para interpolação. Recebidos: {n}")
# Validação da tabela de diferenças divididas
if not isinstance(tabela_diferencas, (list, tuple)):
raise TypeError("tabela_diferencas deve ser uma lista de listas")
if len(tabela_diferencas) == 0:
raise ValueError("tabela_diferencas não pode estar vazia")
if len(tabela_diferencas[0]) != n:
raise ValueError(f"A primeira linha da tabela deve ter {n} elementos. "
f"Recebidos: {len(tabela_diferencas[0])}")
# Validação do grau máximo
max_grau = _validate_max_grau(n, max_grau)
# Conversão e validação do ponto de interpolação
try:
xp = float(xp)
except (ValueError, TypeError):
raise TypeError(f"O ponto de interpolação xp deve ser um número. Recebido: {type(xp)}")
if not np.isfinite(xp):
raise ValueError("O ponto de interpolação xp deve ser finito (não NaN ou infinito)")
# Configuração dos flags de saída
# Se verbose=True e tabela/grafico não forem informados, habilita-os automaticamente
if tabela is None:
tabela = bool(verbose) or globals().get('tabela', False)
if grafico is None:
grafico = bool(verbose) or globals().get('grafico', False)
# Exibição da tabela se solicitado
if tabela:
imprimir_tabela_diferencas_divididas(tabela_diferencas, verbose=verbose)
# Cálculo da interpolação usando diferenças divididas
resultado = float(tabela_diferencas[0][0])
termo = 1.0
if verbose:
print(f"\nCálculo passo a passo - Newton Diferenças Divididas (grau {max_grau}):")
print(f"P({xp}) = f[x₀] = {resultado:.8f}")
termos = [resultado]
for i in range(1, max_grau + 1):
# Cálculo do termo (xp - x[j]) para j = 0 até i-1
termo_parcial = 1.0
termo_str = ""
for j in range(i):
termo_parcial *= (xp - x[j])
if verbose:
termo_str += f"(xp - x[{j}])" if j == 0 else f" · (xp - x[{j}])"
if j < i - 1:
termo_str += " · "
# Adição do termo da diferença dividida
diferenca_dividida = float(tabela_diferencas[i][0])
termo_completo = diferenca_dividida * termo_parcial
resultado += termo_completo
termos.append(termo_completo)
if verbose:
print(f"Termo {i}: f[x₀,x₁,...,x_{i}] = {diferenca_dividida:.8f}")
print(f" {termo_str} = {termo_parcial:.8f}")
print(f" Contribuição: {diferenca_dividida:.8f} × {termo_parcial:.8f} = {termo_completo:.8f}")
print(f" Parcial: {resultado:.8f}")
if verbose:
termos_str = " + ".join([f"{t:.6f}" for t in termos])
print(f"\nP({xp}) = {termos_str} = {resultado:.8f}")
# Geração do gráfico se solicitado
if grafico and verbose:
try:
import matplotlib.pyplot as plt
# Criação da figura
plt.figure(figsize=(10, 6))
# Plot dos pontos originais
plt.plot(x, tabela_diferencas[0], 'ro-', markersize=8, linewidth=2,
label='Pontos de interpolação')
# Plot da curva interpolada
x_min, x_max = min(x), max(x)
margem = 0.1 * (x_max - x_min) if x_max != x_min else 1.0
x_interp = np.linspace(x_min - margem, x_max + margem, 200)
y_interp = [newton_dif_divididas(x, tabela_diferencas, xi, max_grau,
verbose=False, tabela=False, grafico=False)
for xi in x_interp]
plt.plot(x_interp, y_interp, 'b-', linewidth=2,
label=f'Polinômio interpolador (grau {max_grau})')
# Destaque do ponto interpolado
plt.plot([xp], [resultado], 'gx', markersize=12, markeredgewidth=2,
label=f'Ponto interpolado ({xp:.3f}, {resultado:.3f})')
# Configurações do gráfico
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.title(f'Interpolação Newton - Diferenças Divididas (grau {max_grau})',
fontsize=14, fontweight='bold')
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.axhline(y=0, color='k', linestyle='-', alpha=0.3)
plt.axvline(x=0, color='k', linestyle='-', alpha=0.3)
# Ajuste dos limites se necessário
y_min, y_max = min(y_interp), max(y_interp)
y_margem = 0.1 * (y_max - y_min) if y_max != y_min else 1.0
plt.ylim(y_min - y_margem, y_max + y_margem)
plt.tight_layout()
plt.show()
except ImportError:
if verbose:
print("Aviso: Matplotlib não está instalado. Não foi possível gerar o gráfico.")
except Exception as e:
if verbose:
print(f"Aviso: Erro ao gerar gráfico: {e}")
return resultado
[documentos]
def gregory_newton_progressivo(x, y, xp, max_grau=None, verbose=False, tabela=None, grafico=None):
"""Avalia o polinômio interpolador de Gregory-Newton progressivo.
Esta função implementa o método de interpolação polinomial de Gregory-Newton
progressivo, que utiliza diferenças finitas para interpolação em pontos
igualmente espaçados. É uma variante do método de Newton otimizada para
nós com espaçamento uniforme.
Parameters
----------
x, y : array_like
Nós (pontos x) e valores correspondentes (pontos y). Os pontos x devem
estar igualmente espaçados e ser únicos. Ambos devem ser sequências
de números reais finitos.
xp : float
Ponto onde avaliar o polinômio interpolador. Deve ser um número finito.
max_grau : int or None, optional
Grau máximo do polinômio interpolador. Se None (padrão), usa o grau
máximo possível (n-1, onde n é o número de pontos). Deve estar no
intervalo [1, n-1].
verbose : bool, optional
Se True, imprime os cálculos detalhados do processo de interpolação.
Se False (padrão), executa silenciosamente.
tabela : bool or None, optional
Se True, mostra a tabela de diferenças finitas utilizada.
Se None (padrão), usa o valor da variável global 'tabela' ou False.
grafico : bool or None, optional
Se True, gera um gráfico mostrando os pontos originais, a curva
interpolada e o ponto de interpolação. Se None (padrão), usa o valor
da variável global 'grafico' ou False. Requer matplotlib instalado.
Returns
-------
float
Valor interpolado do polinômio de Gregory-Newton no ponto xp.
Raises
------
ValueError
Se as entradas não forem válidas ou se os pontos x não estiverem
igualmente espaçados.
TypeError
Se os tipos de entrada não forem adequados.
Notes
-----
O método de Gregory-Newton progressivo é definido pela fórmula:
.. math::
P_n(x) = y_0 + \\binom{s}{1} \\Delta y_0 + \\binom{s}{2} \\Delta^2 y_0 + \\cdots + \\binom{s}{n} \\Delta^n y_0
onde :math:`s = (x - x_0)/h` é a variável reduzida, :math:`h` é o passo
entre pontos, e :math:`\\Delta^k y_0` são as diferenças finitas progressivas.
Este método requer que os pontos x estejam igualmente espaçados. Para
pontos não-uniformemente espaçados, use newton_dif_divididas.
A complexidade computacional é O(n) para avaliação em um ponto, após
a pré-computação da tabela de diferenças finitas O(n²).
Examples
--------
>>> x = [0, 1, 2, 3]
>>> y = [1, 3, 7, 13] # y = x² + 1
>>> gregory_newton_progressivo(x, y, 1.5)
3.25
>>> # Interpolação cúbica
>>> gregory_newton_progressivo(x, y, 1.5, max_grau=3)
3.25
"""
# Validações de entrada
x, y = _validate_interpolation_inputs(x, y, xp)
n = len(x)
max_grau = _validate_max_grau(n, max_grau)
# Verificação de espaçamento uniforme
espacamento_uniforme, h = verifica_espaçamento_uniforme(x)
if not espacamento_uniforme:
raise ValueError("Os pontos x devem estar igualmente espaçados para "
"o método Gregory-Newton progressivo. Use newton_dif_divididas "
"para pontos não-uniformemente espaçados.")
if abs(h) < 1e-15:
raise ValueError("O espaçamento entre pontos x é muito pequeno ou zero.")
# Conversão e validação do ponto de interpolação
try:
xp = float(xp)
except (ValueError, TypeError):
raise TypeError(f"O ponto de interpolação xp deve ser um número. Recebido: {type(xp)}")
if not np.isfinite(xp):
raise ValueError("O ponto de interpolação xp deve ser finito (não NaN ou infinito)")
# Cálculo da variável reduzida s = (xp - x[0]) / h
s = (xp - x[0]) / h
# Cálculo da tabela de diferenças finitas
tabela_dif_finitas = tabela_diferencas_finitas(y)
# Configuração dos flags de saída
# Se verbose=True e tabela/grafico não forem informados, habilita-os automaticamente
if tabela is None:
tabela = bool(verbose) or globals().get('tabela', False)
if grafico is None:
grafico = bool(verbose) or globals().get('grafico', False)
# Exibição da tabela se solicitado
if tabela:
imprimir_tabela_diferencas_finitas(tabela_dif_finitas, verbose=verbose)
# Cálculo da interpolação usando Gregory-Newton progressivo
resultado = float(y[0])
termo = 1.0
if verbose:
print(f"\nCálculo passo a passo - Gregory-Newton Progressivo (grau {max_grau}):")
print(f"Passo h = {h:.8f}")
print(f"Variável reduzida s = (xp - x[0]) / h = ({xp:.6f} - {x[0]:.6f}) / {h:.8f} = {s:.8f}")
print(f"P({xp:.6f}) = y[0] = {resultado:.8f}")
termos = [resultado]
for k in range(1, max_grau + 1):
# Cálculo do termo binomial: termo *= (s - (k-1)) / k
termo *= (s - (k - 1)) / k
# Diferença finita de ordem k
delta_k = float(tabela_dif_finitas[k][0])
# Contribuição do termo
termo_completo = delta_k * termo
resultado += termo_completo
termos.append(termo_completo)
if verbose:
print(f"Termo {k}: Δ^{k} y[0] = {delta_k:.8f}")
print(f" Binomial: s(s-1)...(s-{k-1})/{k}! = {termo:.8f}")
print(f" Contribuição: {delta_k:.8f} × {termo:.8f} = {termo_completo:.8f}")
print(f" Parcial: {resultado:.8f}")
if verbose:
termos_str = " + ".join([f"{t:.6f}" for t in termos])
print(f"\nP({xp:.6f}) = {termos_str} = {resultado:.8f}")
# Geração do gráfico se solicitado
if grafico and verbose:
try:
import matplotlib.pyplot as plt
# Criação da figura
plt.figure(figsize=(10, 6))
# Plot dos pontos originais
plt.plot(x, y, 'ro-', markersize=8, linewidth=2,
label='Pontos de interpolação')
# Plot da curva interpolada
x_min, x_max = min(x), max(x)
margem = 0.1 * (x_max - x_min) if x_max != x_min else 1.0
x_interp = np.linspace(x_min - margem, x_max + margem, 200)
y_interp = [gregory_newton_progressivo(x, y, xi, max_grau,
verbose=False, tabela=False, grafico=False)
for xi in x_interp]
plt.plot(x_interp, y_interp, 'b-', linewidth=2,
label=f'Polinômio interpolador (grau {max_grau})')
# Destaque do ponto interpolado
plt.plot([xp], [resultado], 'gx', markersize=12, markeredgewidth=2,
label=f'Ponto interpolado ({xp:.3f}, {resultado:.3f})')
# Configurações do gráfico
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.title(f'Interpolação Gregory-Newton Progressivo (grau {max_grau})',
fontsize=14, fontweight='bold')
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.axhline(y=0, color='k', linestyle='-', alpha=0.3)
plt.axvline(x=0, color='k', linestyle='-', alpha=0.3)
# Ajuste dos limites se necessário
y_min, y_max = min(y_interp), max(y_interp)
y_margem = 0.1 * (y_max - y_min) if y_max != y_min else 1.0
plt.ylim(y_min - y_margem, y_max + y_margem)
plt.tight_layout()
plt.show()
except ImportError:
if verbose:
print("Aviso: Matplotlib não está instalado. Não foi possível gerar o gráfico.")
except Exception as e:
if verbose:
print(f"Aviso: Erro ao gerar gráfico: {e}")
return resultado
[documentos]
def lagrange_interpol(x, y, xp, max_grau=None, verbose=False, tabela=None, grafico=None):
"""Avalia o polinômio interpolador de Lagrange em um ponto específico.
Esta função implementa o método de interpolação polinomial de Lagrange,
que constrói um polinômio que passa exatamente pelos pontos dados.
O método é numericamente estável e não requer ordenação prévia dos pontos.
Parameters
----------
x, y : array_like
Nós (pontos x) e valores correspondentes (pontos y). Devem ser sequências
de números reais com o mesmo comprimento. Os pontos x devem ser únicos.
xp : float
Ponto onde avaliar o polinômio interpolador. Deve ser um número finito.
max_grau : int or None, optional
Grau máximo do polinômio interpolador. Se None (padrão), usa o grau
máximo possível (n-1, onde n é o número de pontos). Deve estar no
intervalo [1, n-1].
verbose : bool, optional
Se True, imprime os cálculos detalhados do processo de interpolação.
Se False (padrão), executa silenciosamente.
tabela : bool or None, optional
Se True, mostra tabela com os pontos de interpolação utilizados.
Se None (padrão), usa o valor da variável global 'tabela' ou False.
grafico : bool or None, optional
Se True, gera um gráfico mostrando os pontos originais, a curva
interpolada e o ponto de interpolação. Se None (padrão), usa o valor
da variável global 'grafico' ou False. Requer matplotlib instalado.
Returns
-------
float
Valor interpolado do polinômio de Lagrange no ponto xp.
Raises
------
ValueError
Se as entradas não forem válidas (ver _validate_interpolation_inputs).
TypeError
Se os tipos de entrada não forem adequados.
RuntimeError
Se ocorrer divisão por zero durante o cálculo (pontos x duplicados).
Notes
-----
O método de Lagrange é definido pela fórmula:
.. math::
P(x) = \\sum_{i=0}^{n-1} y_i \\cdot L_i(x)
onde :math:`L_i(x)` são os polinômios base de Lagrange:
.. math::
L_i(x) = \\prod_{j=0, j\\neq i}^{n-1} \\frac{x - x_j}{x_i - x_j}
A complexidade computacional é O(n²) para avaliação em um ponto.
Examples
--------
>>> x = [0, 1, 2]
>>> y = [0, 1, 4]
>>> lagrange_interpol(x, y, 1.5)
2.25
>>> # Interpolação quadrática
>>> lagrange_interpol(x, y, 1.5, max_grau=2)
2.25
"""
# Validações de entrada
x, y = _validate_interpolation_inputs(x, y, xp)
n = len(x)
max_grau = _validate_max_grau(n, max_grau)
# Conversão do ponto de interpolação
try:
xp = float(xp)
except (ValueError, TypeError):
raise TypeError(f"O ponto de interpolação xp deve ser um número. Recebido: {type(xp)}")
if not np.isfinite(xp):
raise ValueError("O ponto de interpolação xp deve ser finito (não NaN ou infinito)")
# Inicialização do resultado
yp = 0.0
# Configuração dos flags de saída
# Se verbose=True e tabela/grafico não forem informados, habilita-os automaticamente
if tabela is None:
tabela = bool(verbose) or globals().get('tabela', False)
if grafico is None:
grafico = bool(verbose) or globals().get('grafico', False)
# Exibição da tabela de pontos se solicitado (detalhes impressos apenas em verbose)
if tabela:
if verbose:
print("\nTabela de pontos de interpolação:")
print(" i | x[i] | y[i] ")
print("---|----------|----------")
for i in range(min(max_grau + 1, n)):
print(f"{i:2d} | {x[i]:10.6f} | {y[i]:10.6f}")
# Cálculo da interpolação
if verbose:
print(f"\nCálculos detalhados do polinômio de Lagrange (grau {max_grau}):")
print(f"P({xp}) = ", end="")
termos = []
for i in range(max_grau + 1):
# Cálculo do polinômio base de Lagrange L_i(xp)
li = 1.0
denominadores = []
if verbose:
print(f"\n Termo {i}: y[{i}] * L{i}({xp})")
print(f" L{i}({xp}) = ", end="")
for j in range(n):
if i != j:
# Verificação de divisão por zero
denominador = x[i] - x[j]
if abs(denominador) < 1e-15:
raise RuntimeError(f"Divisão por zero detectada: x[{i}] - x[{j}] = {denominador}. "
f"Pontos x duplicados ou muito próximos.")
li *= (xp - x[j]) / denominador
denominadores.append(denominador)
if verbose:
print(f"(({xp} - {x[j]:.6f}) / ({x[i]:.6f} - {x[j]:.6f})) ", end="")
# Cálculo do termo completo
termo = y[i] * li
yp += termo
termos.append(termo)
if verbose:
print(f"= {li:.8f}")
print(f" y[{i}] * L{i}({xp}) = {y[i]:.6f} * {li:.8f} = {termo:.8f}")
if verbose:
print(f"\nP({xp}) = {' + '.join([f'{t:.6f}' for t in termos])} = {yp:.8f}")
# Geração do gráfico se solicitado
if grafico and verbose:
try:
import matplotlib.pyplot as plt
# Criação da figura
plt.figure(figsize=(10, 6))
# Plot dos pontos originais
plt.plot(x[:max_grau+1], y[:max_grau+1], 'ro-', markersize=8, linewidth=2,
label='Pontos de interpolação')
# Plot da curva interpolada
x_min, x_max = min(x), max(x)
margem = 0.1 * (x_max - x_min) if x_max != x_min else 1.0
x_interp = np.linspace(x_min - margem, x_max + margem, 200)
y_interp = [lagrange_interpol(x, y, xi, max_grau, verbose=False,
tabela=False, grafico=False)
for xi in x_interp]
plt.plot(x_interp, y_interp, 'b-', linewidth=2,
label=f'Polinômio interpolador (grau {max_grau})')
# Destaque do ponto interpolado
plt.plot([xp], [yp], 'gx', markersize=12, markeredgewidth=2,
label=f'Ponto interpolado ({xp:.3f}, {yp:.3f})')
# Configurações do gráfico
plt.xlabel('x', fontsize=12)
plt.ylabel('y', fontsize=12)
plt.title(f'Interpolação de Lagrange (grau {max_grau})', fontsize=14, fontweight='bold')
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.axhline(y=0, color='k', linestyle='-', alpha=0.3)
plt.axvline(x=0, color='k', linestyle='-', alpha=0.3)
# Ajuste dos limites se necessário
y_min, y_max = min(y_interp), max(y_interp)
y_margem = 0.1 * (y_max - y_min) if y_max != y_min else 1.0
plt.ylim(y_min - y_margem, y_max + y_margem)
plt.tight_layout()
plt.show()
except ImportError:
if verbose:
print("Aviso: Matplotlib não está instalado. Não foi possível gerar o gráfico.")
except Exception as e:
if verbose:
print(f"Aviso: Erro ao gerar gráfico: {e}")
return yp
[documentos]
def dispositivo_pratico_lagrange(x, y, xp, max_grau=None, verbose=False, tabela=None, grafico=None):
x, y = _validate_interpolation_inputs(x, y)
n = len(x)
max_grau = _validate_max_grau(n, max_grau)
resultado = 0.0
G = []
for i in range(n):
linha = []
for j in range(n):
if i == j:
linha.append(xp - x[j])
else:
linha.append(x[i] - x[j])
G.append(linha)
if tabela is None:
tabela = globals().get('tabela', False)
if tabela and verbose:
print("\nDispositivo Prático de Lagrange:")
print(f"{'i':>2} {'x[i]':>10} {'y[i]':>10} {'L[i](xp)':>15}")
for i in range(max_grau + 1):
numerador = 1.0
denominador = 1.0
for j in range(n):
if i != j:
numerador *= (xp - x[j])
denominador *= (x[i] - x[j])
Li = numerador / denominador
print("2d")
for i in range(max_grau + 1):
numerador = 1.0
denominador = 1.0
for j in range(n):
if i != j:
numerador *= (xp - x[j])
denominador *= (x[i] - x[j])
Li = numerador / denominador
termo = y[i] * Li
resultado += termo
if verbose and tabela:
print("\nMatriz G (x[i] - x[j], diagonal = xp - x[i]):")
for linha in G:
print("[ " + " ".join(str(v) for v in linha) + " ]")
if grafico is None:
grafico = globals().get('grafico', False)
if grafico and verbose:
try:
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(x, y, 'ro-', label='Pontos originais')
x_interp = np.linspace(min(x), max(x), 100)
y_interp = [dispositivo_pratico_lagrange(x, y, xi, max_grau, verbose=False, tabela=False, grafico=False) for xi in x_interp]
plt.plot(x_interp, y_interp, 'b-', label=f'Interpolação grau {max_grau}')
plt.plot([xp], [resultado], 'gx', markersize=10, label=f'Ponto interpolado ({xp:.3f}, {resultado:.3f})')
plt.xlabel('x')
plt.ylabel('y')
plt.title(f'Dispositivo Prático de Lagrange (grau {max_grau})')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
except ImportError:
if verbose:
print("Matplotlib não disponível para plotar gráfico.")
return resultado
if __name__ == '__main__':
menu()