Quick Info

Category: Numerical Methods
Time Complexity: O(log n)
Space Complexity: O(1)
Input Type: Continuous Function

Secant Method

Description

The Secant Method is a root-finding algorithm that uses a succession of roots of secant lines to better approximate a root of a function. It is similar to Newton's Method but does not require the computation of derivatives. Instead, it uses a finite difference approximation of the derivative using two points.

How It Works

  1. Initial Setup:
    • Choose two initial points x₀ and x₁ near the suspected root
    • Calculate f(x₀) and f(x₁)
  2. Secant Line:
    • Draw a line through points (x₀, f(x₀)) and (x₁, f(x₁))
    • Find where this line intersects the x-axis
  3. Next Approximation:
    • Use the formula: xₙ₊₁ = xₙ - f(xₙ)(xₙ - xₙ₋₁)/(f(xₙ) - f(xₙ₋₁))
    • This point becomes the new approximation
  4. Iteration:
    • Replace x₀ with x₁
    • Replace x₁ with the new approximation
    • Continue until convergence

History

Carl Friedrich Gauss

The Secant Method has its roots in ancient mathematics, with early versions appearing in the works of Persian mathematician Al-Kashi in the 15th century. The modern form was developed in the 17th century during the scientific revolution. It emerged as a practical alternative to Newton's Method when derivatives were difficult or impossible to compute. The method's name comes from the Latin word "secans," meaning cutting, as it uses secant lines to approximate tangent lines.

Visualization

Click Start to begin visualization

Implementation


def secant_method(f, x0, x1, tolerance=1e-6, max_iterations=100):
    """
    Find root of f(x) = 0 using the secant method.
    
    Args:
        f: Function to find root of
        x0, x1: Initial guesses
        tolerance: Acceptable error
        max_iterations: Maximum number of iterations
    
    Returns:
        Approximate root of f(x)
    """
    fx0 = f(x0)
    
    for i in range(max_iterations):
        fx1 = f(x1)
        
        # Check for division by zero
        if abs(fx1 - fx0) < tolerance:
            raise ValueError("Division by zero in secant method")
        
        # Secant formula
        x2 = x1 - fx1 * (x1 - x0) / (fx1 - fx0)
        
        if abs(x2 - x1) < tolerance:
            return x2
            
        # Update points
        x0, fx0 = x1, fx1
        x1 = x2
    
    raise ValueError("Method failed to converge")

# Example usage
if __name__ == "__main__":
    # Example function: x³ - x - 2
    def f(x): return x**3 - x - 2
    
    # Find root with initial guesses x₀ = 1, x₁ = 2
    root = secant_method(f, 1, 2)
    print(f"Root found at x = {root:.6f}")
    print(f"f({root:.6f}) = {f(root):.6f}")
                                        

#include <iostream>
#include <cmath>
#include <stdexcept>

class SecantMethod {
private:
    double tolerance;
    int maxIterations;
    
public:
    SecantMethod(double tol = 1e-6, int maxIter = 100) 
        : tolerance(tol), maxIterations(maxIter) {}
    
    template<typename F>
    double findRoot(F f, double x0, double x1) {
        double fx0 = f(x0);
        
        for (int i = 0; i < maxIterations; i++) {
            double fx1 = f(x1);
            
            // Check for division by zero
            if (std::abs(fx1 - fx0) < tolerance) {
                throw std::runtime_error(
                    "Division by zero in secant method"
                );
            }
            
            // Secant formula
            double x2 = x1 - fx1 * (x1 - x0) / (fx1 - fx0);
            
            if (std::abs(x2 - x1) < tolerance)
                return x2;
                
            // Update points
            x0 = x1;
            fx0 = fx1;
            x1 = x2;
        }
        
        throw std::runtime_error("Method failed to converge");
    }
};

int main() {
    // Example function: x³ - x - 2
    auto f = [](double x) { return x*x*x - x - 2; };
    
    SecantMethod solver;
    try {
        double root = solver.findRoot(f, 1.0, 2.0);
        std::cout << "Root found at x = " << root << std::endl;
        std::cout << "f(" << root << ") = " << f(root) << std::endl;
    }
    catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    
    return 0;
}
                                        

public class SecantMethod {
    private readonly double tolerance;
    private readonly int maxIterations;
    
    public SecantMethod(double tolerance = 1e-6, int maxIterations = 100) {
        this.tolerance = tolerance;
        this.maxIterations = maxIterations;
    }
    
    public double FindRoot(Func<double, double> f, double x0, double x1) {
        double fx0 = f(x0);
        
        for (int i = 0; i < maxIterations; i++) {
            double fx1 = f(x1);
            
            // Check for division by zero
            if (Math.Abs(fx1 - fx0) < tolerance) {
                throw new InvalidOperationException(
                    "Division by zero in secant method"
                );
            }
            
            // Secant formula
            double x2 = x1 - fx1 * (x1 - x0) / (fx1 - fx0);
            
            if (Math.Abs(x2 - x1) < tolerance)
                return x2;
                
            // Update points
            x0 = x1;
            fx0 = fx1;
            x1 = x2;
        }
        
        throw new InvalidOperationException("Method failed to converge");
    }
    
    public static void Main() {
        // Example function: x³ - x - 2
        double f(double x) => x * x * x - x - 2;
        
        var solver = new SecantMethod();
        try {
            double root = solver.FindRoot(f, 1.0, 2.0);
            Console.WriteLine($"Root found at x = {root:F6}");
            Console.WriteLine($"f({root:F6}) = {f(root):F6}");
        }
        catch (Exception e) {
            Console.WriteLine($"Error: {e.Message}");
        }
    }
}
                                        

Complexity Analysis

Time Complexity

The time complexity is O(log n), where:

  • n is the desired precision (1/ε)
  • Convergence rate is superlinear (≈ 1.618)
  • Faster than bisection method
  • Slower than Newton's method

Space Complexity

The space complexity is O(1), which includes:

  • Storage for two points
  • Storage for function values
  • No additional data structures needed

Advantages and Disadvantages

Advantages

  • No derivatives required
  • Faster convergence than bisection
  • Simple to implement
  • Works well for smooth functions

Disadvantages

  • May diverge for poor initial guesses
  • Slower than Newton's method
  • No guaranteed convergence
  • Sensitive to choice of initial points