Código-fonte para CB2325NumericaG1.raizes.raizes_newton_raphson

import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from typing import Callable, Union

[documentos] def newton_raphson(function: Union[Callable, sp.Basic], guess: float, tolerance: float, plot: bool = False) -> float: """ Encontra/aproxima uma raiz de uma função real de variável real usando o método de Newton–Raphson. Calcula onde a reta tangente ao gráfico da função no ponto x0 cruza o eixo x. Repete o processo com esse novo ponto x1. Args: function Union[Callable, sp.Basic]: Função cuja raíz queremos encontrar ou aproximar. Pode ser Callable ou sp.Basic. Para melhor eficiência do método, deve ser sp.Basic. guess (float): Chute inicial x0. tolerance (float): Critério de parada. O método para quando |f| < tolerance ou |dx| < tolerance. plot (bool = False): Determina se uma visualização gráfica do método será plotada. Por padrão, não será. Returns: float: Valor aproximado da raiz. Raises: ValueError: Se a expressão SymPy tiver mais de uma variável. Se ocorrer NaN/Inf em algum momento da iteração. Se em algum momento da iteração o ponto xn nao estiver no domínio da f ou da df TypeError: Se function não for Callable ou sp.Basic. ZeroDivisionError: Se a derivada praticamente zerar em algum momento da iteração. RunTimeError: Se o método não convergir em no máximo 1000 iterações. """ MAX_ITERS = 1000 x0 = float(guess) x_record = [x0] # Preparar f e df: se function for sympy, obtenha a derivada analítca; # caso contrário, use derivada numérica por quociente de newton. if isinstance(function, sp.Basic): # cobre sp.Expr, sp.Symbol, etc. if isinstance(function, sp.Lambda): f_expr = function.expr variables = function.variables else: # é uma expressão sp.Basic f_expr = function variables = function.free_symbols # Garante que é uma função de uma variável if len(variables) == 0: # Caso constante f = lambda x: float(f_expr) df = lambda x: 0.0 elif len(variables) == 1: x_sym = list(variables)[0] f = sp.lambdify(x_sym, f_expr, 'numpy') df_expr = sp.diff(f_expr, x_sym) df = sp.lambdify(x_sym, df_expr, 'numpy') else: raise ValueError(f"A expressão SymPy deve ter exatamente uma variável, mas foram encontradas {len(variables)}: {variables}") elif callable(function): f = function def df(x): h = 1e-8 return (f(x + h) - f(x - h)) / (2.0 * h) # Caso 3: Entrada inválida else: raise TypeError("function deve ser Callable ou sp.Basic.") root = None fx = None for i in range(MAX_ITERS): try: fx_val = f(x0) fx = float(fx_val) except Exception as e: raise ValueError(f"f não pode ser avaliada em {x0}: {e}") if np.isnan(fx) or np.isinf(fx): raise ValueError(f"f(x) retornou {fx} no ponto x = {x0}.") if abs(fx) < tolerance: root = x0 break try: dfx_val = df(x0) dfx = float(dfx_val) except Exception as e: raise ValueError(f"f' não pode ser avaliada em {x0}: {e}") if np.isnan(dfx) or np.isinf(dfx): raise ValueError(f"f'(x) retornou {dfx} no ponto x = {x0}.") if abs(dfx) < 1e-16: raise ZeroDivisionError(f"Derivada muito próxima de zero em x = {x0}.") x1 = x0 - fx / dfx x_record.append(x1) # Critérios de parada if abs(x1 - x0) < tolerance: root = x1 break x0 = x1 if root is None: raise RuntimeError(f"Não convergiu após {MAX_ITERS} iterações. Último x = {x0}, f(x) = {fx}") # Visualização gráfica if plot: if len(x_record) > 1: x_min = min(x_record) x_max = max(x_record) delta = (x_max - x_min) * 0.1 if x_max > x_min else 1.0 x_min -= delta x_max += delta else: x_min = x_record[0] - 1.0 x_max = x_record[0] + 1.0 x = np.linspace(x_min, x_max, 100) y = f(x) # Plota a função original em preto. plt.plot(x, y, color='black', linewidth=1, label='f(x)') # Plota os pontos de iteração x_points_y = f(np.array(x_record)) plt.plot(x_record, x_points_y, 'ro', label='Pontos de Iteração') # Plota os segmentos de reta tangente pontilhados for j in range(len(x_record) - 1): x_i = x_record[j] y_i = float(f(x_i)) x_next = x_record[j + 1] x_tang = np.array([x_i, x_next]) y_tang = df(x_i) * (x_tang - x_i) + y_i plt.plot(x_tang, y_tang, 'b--', label='Tangente' if j == 0 else None) # Plota o eixo x. plt.axhline(0, color='black', linewidth=1) # Configuração do gráfico plt.axis('equal') plt.title("Raízes da função pelo Método de Newton-Raphson") plt.grid(True, linestyle='--', alpha=0.6) plt.xlabel("x") plt.ylabel("f(x)") plt.legend() plt.show() return root