import math
import matplotlib.pyplot as plt
from sympy import symbols, diff, lambdify
# Function to evaluate user input function
def evaluate_function(func_str, x):
return eval(func_str)
# Newton-Raphson Method
def newton_raphson_method(func_str, df_func_str, x0, tol=0.1, max_iter=100,
true_root=None):
iteration_data = []
ea_values = [] # To store Ea for plotting
iteration_numbers = [] # To store iteration numbers for plotting
x = x0 # Initial guess
# Table header for Newton-Raphson
print("\nNewton-Raphson Method:")
print(f"{'n':<5}{'x_n':<12}{'f(x_n)':<12}{'f\'(x_n)':<12}{'Ea (%)':<12}{'Et
(%)':<12}")
print("-" * 70)
for i in range(max_iter):
f_x = evaluate_function(func_str, x)
df_x = evaluate_function(df_func_str, x)
# Avoid division by zero
if df_x == 0:
print("Zero derivative encountered, method fails.")
break
# Update x using Newton-Raphson formula
x_new = x - (f_x / df_x)
# Calculate approximate relative error (Ea)
if i > 0:
ea = abs((x_new - x) / x_new) * 100
else:
ea = None
# Calculate true relative error (Et), if true root is provided
if true_root is not None:
et = abs((true_root - x) / true_root) * 100
else:
et = None
# Store iteration data
iteration_data.append((i, x, f_x, df_x, ea, et))
# Store data for plotting
iteration_numbers.append(i) # Iteration number
ea_values.append(ea)
# Print row
print(f"{i:<5}{x:<12.6f}{f_x:<12.6f}{df_x:<12.6f}{f'{ea:.6f}' if ea is not
None else 'N/A':<12}{f'{et:.6f}' if et is not None else 'N/A':<12}")
# Check if tolerance is met
if ea is not None and ea < tol:
break
x = x_new # Update x for next iteration
return iteration_data, ea_values, iteration_numbers
# Secant Method
def secant_method(func_str, x0, x1, tol=0.1, max_iter=100, true_root=None):
iteration_data = []
ea_values = [] # To store Ea for plotting
iteration_numbers = [] # To store iteration numbers for plotting
x_prev = x0
x_curr = x1 # Initial guesses
# Table header for Secant Method
print("\nSecant Method:")
print(f"{'n':<5}{'x_n':<12}{'f(x_n)':<12}{'Ea (%)':<12}{'Et (%)':<12}")
print("-" * 60)
for i in range(max_iter):
f_x_prev = evaluate_function(func_str, x_prev)
f_x_curr = evaluate_function(func_str, x_curr)
# Avoid division by zero
if f_x_curr - f_x_prev == 0:
print("Zero denominator encountered, method fails.")
break
# Update x using Secant formula
x_new = x_curr - f_x_curr * (x_curr - x_prev) / (f_x_curr - f_x_prev)
# Calculate approximate relative error (Ea)
if i > 0:
ea = abs((x_new - x_curr) / x_new) * 100
else:
ea = None
# Calculate true relative error (Et), if true root is provided
if true_root is not None:
et = abs((true_root - x_curr) / true_root) * 100
else:
et = None
# Store iteration data
iteration_data.append((i, x_curr, f_x_curr, ea, et))
# Store data for plotting
iteration_numbers.append(i) # Iteration number
ea_values.append(ea)
# Print row
print(f"{i:<5}{x_curr:<12.6f}{f_x_curr:<12.6f}{f'{ea:.6f}' if ea is not
None else 'N/A':<12}{f'{et:.6f}' if et is not None else 'N/A':<12}")
# Check if tolerance is met
if ea is not None and ea < tol:
break
x_prev = x_curr
x_curr = x_new
return iteration_data, ea_values, iteration_numbers
# Plotting function for both methods in separate subplots
def plot_ea_vs_iterations_subplots(iteration_numbers_newton, ea_values_newton,
iteration_numbers_secant, ea_values_secant):
fig, axs = plt.subplots(1, 2, figsize=(12, 6)) # Create a single figure with
two subplots (1 row, 2 columns)
# Plot Newton-Raphson Method on the first subplot
axs[0].plot(iteration_numbers_newton[1:], ea_values_newton[1:], 'bo-',
label='Newton-Raphson Method Ea (%)')
axs[0].set_xlabel('Iteration Number')
axs[0].set_ylabel('Ea (%)')
axs[0].set_title('Newton-Raphson Method')
axs[0].grid(True)
axs[0].legend()
# Plot Secant Method on the second subplot
axs[1].plot(iteration_numbers_secant[1:], ea_values_secant[1:], 'ro-',
label='Secant Method Ea (%)')
axs[1].set_xlabel('Iteration Number')
axs[1].set_ylabel('Ea (%)')
axs[1].set_title('Secant Method')
axs[1].grid(True)
axs[1].legend()
# Adjust layout to prevent overlap
plt.tight_layout()
plt.show()
# Main Execution
try:
# Asking user for inputs
func_str = input("Enter the function in terms of x (e.g., 'x**3 - 5*x**2 + 6*x
- 2'): ")
# Generate derivative of the function for Newton-Raphson Method
x_sym = symbols('x')
func_sym = eval(func_str)
df_func_sym = diff(func_sym, x_sym)
df_func_str = str(df_func_sym)
print(f"Derived function for Newton-Raphson: f'(x) = {df_func_str}")
x0_newton = float(input("Enter the initial guess for Newton-Raphson Method: "))
x0_secant = float(input("Enter the first initial guess for Secant Method: "))
x1_secant = float(input("Enter the second initial guess for Secant Method: "))
tol = float(input("Enter the stopping criterion (tolerance, e.g. 0.1, 0.5): "))
max_iter = int(input("Enter the maximum number of iterations: "))
true_root = float(input("Enter the true root (if known, otherwise enter 0): "))
or None
# Run the Newton-Raphson Method
newton_data, ea_values_newton, iteration_numbers_newton =
newton_raphson_method(func_str, df_func_str, x0_newton, tol, max_iter, true_root)
# Run the Secant Method
secant_data, ea_values_secant, iteration_numbers_secant =
secant_method(func_str, x0_secant, x1_secant, tol, max_iter, true_root)
# Plot the Ea vs Iterations graphs for both methods in subplots
if newton_data and secant_data:
plot_ea_vs_iterations_subplots(iteration_numbers_newton, ea_values_newton,
iteration_numbers_secant, ea_values_secant)
except ValueError:
print("Invalid input. Please enter numerical values.")
except Exception as e:
print(f"An error occurred: {e}")