Considere o vetor \vec{V}=\left[x_{0}, \ldots, x_{6}\right] e \vec{W}=\left[f\left(x_{0}\right), \ldots, f\left(x_{s}\right)\right] com x_{0}, \ldots, x_{6} diferentes (obrigatório). Faça um programa que calcula o polinômio interpolador aplicado em X, por forma de Lagrange.

Passo 1

O que o enunciado dá e o que pede (resumido, bem claro):
  • Dados: um vetor \vec{V} = [x_{0},\ldots,x_{6}] com x_{0},\ldots,x_{6} todos diferentes (isto é obrigatório) e um vetor \vec{W} = [f(x_{0}),\ldots,f(x_{6})].
  • Pedido: fazer um programa que calcule o polinômio interpolador de Lagrange a partir desses pares (x_j,f(x_j)) e retorne o valor do polinômio avaliado em um ponto X (isto é, calcular P(X), onde P é o polinômio interpolador).
  • Observações importantes que vêm do enunciado:
    • Existem exatamente 7 nós no exemplo dado (índices de 0 a 6), portanto o polinômio interpolador terá grau no máximo 6.
    • Os x_j são todos distintos — se não forem, a interpolação no sentido clássico de Lagrange não é definida.
    • O programa deve cuidar do caso especial em que X coincide com algum x_j: então P(X)=f(x_j) (deve retornar esse valor sem tentativa de divisão por zero).

Passo 2

Fórmula de Lagrange (o que precisamos implementar) — apresentação e significado de cada símbolo:
  • Seja n o número de nós menos 1. No seu caso n=6, mas o código será geral. O polinômio interpolador de Lagrange é
P(x)=\sum_{j=0}^{n} f(x_j)\, \ell_j(x),
onde cada polinômio base \ell_j(x) é dado por
\ell_j(x)=\prod_{\substack{m=0\\\ m\ne j}}^{n}\frac{x-x_m}{x_j-x_m}.
  • Explicando: para calcular P(X) avaliado em um ponto X,
    • para cada j faz-se o produto sobre todos os m\neq j de \dfrac{X-x_m}{x_j-x_m} para obter \ell_j(X),
    • multiplica-se \ell_j(X) por f(x_j),
    • e soma-se sobre j=0,\ldots,n.
  • Variáveis e significados:
    • x_j são os nós conhecidos (elementos de \vec{V}).
    • f(x_j) são os valores conhecidos (elementos de \vec{W}).
    • X é o ponto onde se quer avaliar o polinômio interpolador.
    • n é o grau máximo (aqui n=6, mas o algoritmo funciona para qualquer n).

Passo 3

Estratégia computacional e cuidados numéricos simples (como fazer na prova sem calculadora e como traduzir para código):
  • Estratégia direta (fácil de entender e suficiente para n=6):
    1. Verificar que os vetores \vec{V} e \vec{W} têm o mesmo tamanho n+1.
    2. Verificar que todos os x_j são distintos (caso contrário abortar/lançar erro).
    3. Se X for (praticamente) igual a algum x_j, retornar imediatamente f(x_j).
    4. Para cada j=0,\ldots,n:
      • calcular o produto d_j=\prod_{m\ne j}(x_j-x_m) (denominador fixo que depende só dos nós; pode ser pré-calculado),
      • calcular o produto p_j(X)=\prod_{m\ne j}(X-x_m) (numerador que depende do X),
      • então \ell_j(X)=\dfrac{p_j(X)}{d_j} e contribui para P(X) com f(x_j)\,\ell_j(X).
    5. Somar todas as contribuições para obter P(X).
  • Complexidade: a versão direta faz O(n^2) operações aritméticas (para n=6 isso é trivialmente rápido).
  • Atenção numérica: dividir por números muito pequenos pode aumentar erro; para usos numéricos críticos existe a fórmula barycêntrica de Lagrange (mais estável), mas aqui a forma direta é a que o enunciado pediu e é adequada para a prova e para pequenos n.
  • Nota prática: ao comparar X com x_j usar uma comparação com tolerância numérica (por ex. usando uma função de igualdade aproximada) para evitar problemas com floats.

Passo 4

Algoritmo passo a passo convertido em pseudocódigo (para ficar claro antes do código real):
  1. Receber listas/arrays x e y e ponto X.
  2. Definir n = comprimento de x menos 1.
  3. Se comprimento de y diferente de comprimento de x -> erro.
  4. Para cada par i<j verificar se x_i = x_j (ou muito próximo) -> erro se houver repetição.
  5. Para cada j=0 até n: se X é aproximadamente igual a x_j retorna y_j.
  6. Calcular os denominadores d_j=\prod_{m\ne j}(x_j-x_m) e guardá-los.
  7. Inicializar soma total S=0.
  8. Para cada j=0 até n:
    • calcular p_j=\prod_{m\ne j}(X-x_m),
    • \ell_j(X)=p_j/d_j,
    • S \leftarrow S + y_j\cdot \ell_j(X).
  9. Retornar S P(X)).

Passo 5

Código Python (implementação prática, limpa e comentada). Este código segue exatamente a estratégia anterior e trata dos casos especiais:
  • usa verificação de igualdade aproximada com math.isclose;
  • pré-calcula denominadores para evitar fazer os mesmos produtos repetidos desnecessariamente;
  • funciona para qualquer tamanho de entrada, inclusive o caso do enunciado com 7 nós.
import math

def lagrange_interpolate(x, y, X, rel_tol=1e-12, abs_tol=1e-12):
    """
    Interpola pelos pontos (x[i], y[i]) usando a forma de Lagrange
    e retorna P(X), onde P é o polinômio interpolador.
    - x: lista/iterável de nós x_0,...,x_n (todos distintos)
    - y: lista/iterável de valores f(x_0),...,f(x_n)
    - X: ponto onde avaliar o polinômio
    - rel_tol, abs_tol: tolerâncias para comparar floats (uso em isclose)
    """
    n = len(x)
    if len(y) != n:
        raise ValueError("x e y devem ter o mesmo tamanho")
    if n == 0:
        raise ValueError("pelo menos um ponto é necessário")

    # Checar nós distintos
    for i in range(n):
        for j in range(i+1, n):
            if math.isclose(x[i], x[j], rel_tol=rel_tol, abs_tol=abs_tol):
                raise ValueError("Os nós x devem ser todos distintos")

    # Se X coincide com algum nó, retorna o valor correspondente
    for i, xi in enumerate(x):
        if math.isclose(X, xi, rel_tol=rel_tol, abs_tol=abs_tol):
            return y[i]

    # Pré-calcular denominadores d_j = prod_{m != j} (x_j - x_m)
    denominators = [1.0] * n
    for j in range(n):
        prod = 1.0
        xj = x[j]
        for m in range(n):
            if m == j:
                continue
            prod *= (xj - x[m])
        denominators[j] = prod

    # Calcular P(X) pela soma das contribuições y_j * l_j(X)
    total = 0.0
    for j in range(n):
        numer = 1.0
        for m in range(n):
            if m == j:
                continue
            numer *= (X - x[m])
        lj = numer / denominators[j]
        total += y[j] * lj

    return total

# Exemplo de uso:
if __name__ == "__main__":
    # exemplo simples com 3 nós (pode usar 7 como no enunciado)
    xv = [0.0, 1.0, 2.0]
    yv = [1.0, 3.0, 7.0]   # p(x)=1 + 2x + x^2 -> p(1.5)=1 + 3 + 2.25 = 6.25
    X = 1.5
    print("P({}) = {}".format(X, lagrange_interpolate(xv, yv, X)))

Passo 6

Explicação linha a linha do código (mapa entre fórmula e implementação), para você saber aplicar isso na prova:
  • A checagem de tamanhos garante que cada x_j tem um y_j correspondente. Sem isso a soma \sum_{j=0}^n f(x_j)\ell_j(x) não faz sentido.
  • A verificação de nós distintos impede divisão por zero nos denominadores \prod_{m\ne j}(x_j-x_m).
  • O laço que testa se X coincide com algum x_j é a aplicação direta da observação: se X=x_j então todos os \ell_m(X) são zero exceto \ell_j(X)=1, logo P(X)=f(x_j). Isto evita divisão por valores muito pequenos e é matematicamente exato.
  • O cálculo dos denominadores implementa d_j=\prod_{\substack{m=0\\\ m\ne j}}^{n}(x_j-x_m),que é précomputado porque depende apenas dos nós.
  • Para cada j calculamos p_j(X)=\prod_{\substack{m=0\\\ m\ne j}}^{n}(X-x_m), \qquad \ell_j(X)=\frac{p_j(X)}{d_j},e acumulamos y_j\cdot \ell_j(X) na soma total.
  • O retorno é exatamente P(X), pela fórmula de Lagrange.

Passo 7

Observações finais, dicas rápidas e incentivo:
  • Para o enunciado com exatamente 7 nós, basta passar listas de tamanho 7 para a função e ela retorna P(X).
  • Se for necessária muita precisão numérica ou muitos pontos, estude a fórmula barycêntrica de Lagrange (é essencial para estabilidade e eficiência), mas para provas e para n=6 a forma direta é totalmente aceitável.
  • Você já consegue implementar isso na prova: pense nos produtos (numerador/denominador) e na soma final — siga os passos e cheque o caso X=x_j. Vai dar certo — confia no processo! 😃

Resposta

import math

def lagrange_interpolate(x, y, X, rel_tol=1e-12, abs_tol=1e-12):
    """
    Interpola pelos pontos (x[i], y[i]) usando a forma de Lagrange
    e retorna P(X), onde P é o polinômio interpolador.
    - x: lista/iterável de nós x_0,...,x_n (todos distintos)
    - y: lista/iterável de valores f(x_0),...,f(x_n)
    - X: ponto onde avaliar o polinômio
    - rel_tol, abs_tol: tolerâncias para comparar floats
    """
    n = len(x)
    if len(y) != n:
        raise ValueError("x e y devem ter o mesmo tamanho")
    if n == 0:
        raise ValueError("pelo menos um ponto é necessário")

    # Checar nós distintos
    for i in range(n):
        for j in range(i+1, n):
            if math.isclose(x[i], x[j], rel_tol=rel_tol, abs_tol=abs_tol):
                raise ValueError("Os nós x devem ser todos distintos")

    # Se X coincide com algum nó, retorna o valor correspondente
    for i, xi in enumerate(x):
        if math.isclose(X, xi, rel_tol=rel_tol, abs_tol=abs_tol):
            return y[i]

    # Pré-calcular denominadores d_j = prod_{m != j} (x_j - x_m)
    denominators = [1.0] * n
    for j in range(n):
        prod = 1.0
        xj = x[j]
        for m in range(n):
            if m == j:
                continue
            prod *= (xj - x[m])
        denominators[j] = prod

    # Calcular P(X) pela soma das contribuições y_j * l_j(X)
    total = 0.0
    for j in range(n):
        numer = 1.0
        for m in range(n):
            if m == j:
                continue
            numer *= (X - x[m])
        lj = numer / denominators[j]
        total += y[j] * lj

    return total

# Exemplo de uso:
if __name__ == "__main__":
    # exemplo com 7 nós (pode trocar pelos seus dados)
    xv = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
    yv = [1.0, 2.0, 5.0, 10.0, 17.0, 26.0, 37.0]  # exemplo qualquer
    X = 2.5
    print("P({}) = {}".format(X, lagrange_interpolate(xv, yv, X)))

Exercícios relacionados