Find Function Roots With Iteration and Convergence
Find roots of functions using Newton-Raphson and Bisection methods. Enter a function expression, choose your method, and watch the iteration converge.
Solving f(x) = 0 when there's no closed form is the use case. Bisection brackets a root between a and b with f(a)·f(b) < 0 and halves the interval each step. Every iteration buys roughly one bit of precision, so reaching 10⁻⁸ from a unit-width bracket takes about 27 steps. Slow, but unconditionally convergent as long as the bracket is valid.
Newton's method uses the derivative: x_{n+1} = x_n − f(x_n) / f'(x_n). Convergence is quadratic near the root, so error roughly squares each step and machine precision lands in 5–7 iterations from a decent starting guess. The cost: it can diverge, oscillate, or land on the wrong root if you start too far away or near a critical point of f. Brent's method is the standard hybrid in practice, combining bisection's safety with secant-style speed; it's what scipy.optimize.brentq calls under the hood. The page runs Newton, bisection, and Brent on the same f and reports the iteration trace for each, so you can see convergence behavior directly rather than just trusting a "converged" flag.
Choose Method: Bisection vs Newton-Raphson
Bisection brackets the root between two points where f changes sign. Each iteration halves the interval, guaranteeing convergence but taking 20–50 iterations for typical tolerances. It never fails if you start with a valid bracket (f(a) and f(b) have opposite signs).
Newton-Raphson uses the derivative to leap toward the root: x_{n+1} = x_n − f(x_n)/f′(x_n). When it works, convergence is quadratic—error roughly squares each step, reaching machine precision in 5–10 iterations. But it requires a good initial guess and can fail if f′ is zero or nearly so.
Use bisection when you're unsure of starting conditions or when the function is poorly behaved. Use Newton when you have a reasonable guess and the derivative is available. A hybrid approach—bisection to narrow down, then Newton to finish—combines reliability with speed.
Convergence comparison:
• Bisection: linear, ~1 bit per iteration
• Newton: quadratic, doubles correct digits per iteration
Bracketing and Start Values That Matter
For bisection, pick [a, b] so f(a) and f(b) have opposite signs. The Intermediate Value Theorem guarantees at least one root inside. If both values share a sign, either there's no root in that interval or an even number of roots that cancel out. Narrow the bracket visually by plotting first.
For Newton, start near where you expect the root. A guess too far away can send iterations off to infinity or to a different root. Plot f(x) to identify approximate crossings. If the function has multiple roots, different starting guesses find different roots.
Critical points (where f′ = 0) trap Newton. If your guess lands near a local extremum, the tangent line is nearly horizontal, and the next step jumps far away. Avoid starting exactly at extrema. Bisection doesn't care about extrema inside the bracket.
Practical tip: Run a few bisection iterations to narrow down the region, then switch to Newton with that midpoint as the initial guess. You get reliability plus speed.
Convergence Table: Iterations and Error
The iteration table shows how each step refines the approximation. For Newton, watch the error shrink rapidly—if error is 10⁻² at step 3, it might be 10⁻⁴ at step 4, then 10⁻⁸ at step 5. That's quadratic convergence in action.
Bisection's table shows the interval halving. Error decreases by a factor of 2 each iteration. To get from 10⁻¹ to 10⁻⁶ requires about 17 halvings (since 2¹⁷ ≈ 130,000). Predictable but slow compared to Newton's geometric leaps.
Convergence stops when |f(x)| drops below the tolerance or when successive approximations differ by less than the tolerance. If iterations max out without meeting the tolerance, the method didn't converge—check your starting conditions or function behavior.
Newton iteration:
x_{n+1} = x_n − f(x_n) / f′(x_n)
Stop when |f(x_{n+1})| < tolerance or |x_{n+1} − x_n| < tolerance
Multiple Roots and Flat Slopes (Failure Cases)
A repeated root (like x² = 0 at x = 0) slows Newton to linear convergence because f and f′ both vanish at the root. The formula x − f/f′ becomes 0/0 in the limit. Special modifications (like modified Newton) handle this, but basic implementations struggle.
Flat slopes (f′ ≈ 0 away from the root) cause wild jumps. If the tangent line is nearly horizontal, the x-intercept lies far away. One bad step can throw iterations off to infinity or into oscillation between distant values.
Bisection fails if the interval lacks a sign change—either no root exists inside, or an even number of roots cancel out (f dips below zero then returns above without crossing back). Always verify that f(a) × f(b) < 0 before relying on bisection.
Warning: If Newton oscillates or diverges, try a different starting guess. If bisection claims no root, widen your interval or plot the function to see what's happening.
Plot Overlay: Where f(x) Crosses Zero
The graph shows f(x) with the x-axis. Roots appear where the curve crosses zero. Plotting before computing tells you roughly where to start and how many roots exist in your range. Multiple crossings mean multiple roots—each requires a separate run.
Iteration points can be overlaid on the plot. For Newton, see how each tangent line jumps to the next approximation. For bisection, watch the interval shrink around the crossing. Visual feedback clarifies why convergence succeeds or fails.
Near-miss roots (where f gets close to zero but doesn't cross) can trick visual inspection. Zoom in to confirm the curve actually crosses or merely grazes the axis. A grazing touch means a repeated root or no root at all in the strict sense.
Graph tip: Set the plot range to include the entire region of interest. If roots lie at x = −5 and x = 10, a range of [−10, 15] shows both, preventing you from missing one.
Root-Finding Q&A
Why does Newton converge faster than bisection?
Newton uses derivative information to make informed jumps, roughly doubling correct digits each step. Bisection ignores derivatives and just halves the interval, gaining about one bit of precision per iteration. More information yields faster convergence.
What if I don't know the derivative?
You can approximate it numerically: f′(x) ≈ (f(x + h) − f(x − h)) / (2h) for small h. The secant method uses past function values instead of derivatives. Both work when analytic derivatives are unavailable.
Can these methods find complex roots?
As implemented for real numbers, no. Complex roots require working in the complex plane. Newton-Raphson generalizes to complex inputs, but bisection (which relies on sign changes) doesn't apply. Use specialized polynomial solvers for complex roots.
How do I find all roots of a function?
Run the method multiple times with different starting guesses or intervals. Alternatively, use deflation: after finding one root r, divide out (x − r) and find the next. Plot first to count approximate root locations.
The method says "converged" but f(root) isn't zero. What happened?
Convergence criteria check if progress stalls, not if f equals zero. If |x_{n+1} − x_n| falls below tolerance but f(x) is still sizable, the method stopped near a flat region. Tighten tolerance or start from a better guess.
Limitations of iterative root-finding
Newton can fail: the method diverges, oscillates, or lands on the wrong root if the starting guess is too far from the actual root or near a critical point of f. Quadratic convergence is fast when it works. The cost is fragility.
Bisection is slow but safe: unconditionally convergent given a valid bracket (f(a)·f(b) < 0), but only buys one bit of precision per iteration. For 10⁻⁸ accuracy from a unit-width bracket that's about 27 steps.
One root per run: multiple roots in the search interval mean you'll find one and miss the others. Plot f first, then run separate searches from different starting conditions.
Float64 precision floor: double-precision arithmetic caps useful accuracy near 15 significant digits. Tolerances tighter than 10⁻¹⁴ won't actually improve the answer and can cause spurious failures.
Note: Brent's method is the standard hybrid in production: bisection's safety with secant's speed. scipy.optimize.brentq is what most numerical Python code calls. MATLAB's fzero is the equivalent. Burden & Faires' "Numerical Analysis" is the standard reference for the iterative methods themselves.
Sources & References
Methods and algorithms follow standard numerical analysis references:
- •Wolfram MathWorld: Newton's Method
- •MIT OpenCourseWare: Introduction to Numerical Analysis
- •Numerical Recipes: Root Finding Algorithms
Iterative root-finding: working questions
Newton vs bisection, which one converges faster?
Newton, when it works. Newton has quadratic convergence near a simple root: error roughly squares each iteration. Going from 10⁻² to 10⁻¹⁶ takes about 4 iterations. Bisection has linear convergence: each step gains exactly one bit (10⁻⁸ from a unit-width bracket takes 27 steps). The catch: Newton can diverge or land on the wrong root if the starting guess is bad, while bisection is unconditionally convergent given a valid sign-change bracket. The standard practice is hybrid (Brent's method): bisection's safety with secant or Newton's speed near the root.
When does Newton's method diverge?
Several failure modes. Starting too far from the root, where higher-order terms dominate. Hitting a critical point where f'(x) = 0 (the iteration step is f/f', which blows up). Approaching a vertical asymptote. Functions with multiple roots where the iteration oscillates. Inflection points near the start. Practical fix: plot f first, pick a starting guess close to the apparent root, and check that the iteration is contracting (each step smaller than the last). If it isn't, switch to bisection on a bracket you can verify.
How do I find all roots of a function?
There's no general algorithm. The standard approach: plot f over the range of interest, identify all sign changes visually, then run a local method (Newton, secant, Brent) starting from each one. For polynomials, np.roots in Python and roots() in MATLAB return all roots (real and complex) by computing eigenvalues of the companion matrix. For transcendental equations, deflation can extract roots one at a time: after finding root r₁, work on g(x) = f(x) / (x − r₁). Multiple roots within one bracket need extra care; bisection only finds one per bracket.
What's a good initial guess for Newton's method?
Close to the root, on the side where f is well-behaved. Quantitatively, the basin of attraction is bounded by the nearest critical point and the nearest inflection point that pushes the iteration the wrong way. If you can plot f, eyeball the root and pick a starting point within 10-20% of it. Without a plot, start with x₀ that has the right order of magnitude and small |f(x₀)|. If Newton diverges or oscillates from your guess, run a few bisection steps first to narrow the bracket, then hand off to Newton.
What does the tolerance setting actually control?
Two stopping criteria, often both. Function tolerance: stop when |f(x)| < ε_f. Step tolerance: stop when |x_{n+1} − x_n| < ε_x. The two aren't equivalent: |f| can be small while |x − root| is meaningfully nonzero (flat function near the root), and vice versa near a steep slope. Default tolerances around 10⁻⁸ are reasonable for double precision. Tightening below 10⁻¹⁴ won't actually improve the answer because float64 only has ~15 digits of precision, and you may trigger spurious failures from round-off.
Why is Brent's method the production default?
It combines bisection's guaranteed convergence with secant's speed via inverse quadratic interpolation. The algorithm picks bisection when the iteration looks unsafe (interpolation overshoots, doesn't contract enough) and a fast method otherwise. Result: never worse than bisection, usually as fast as Newton without needing the derivative. scipy.optimize.brentq is what most numerical Python code calls. MATLAB's fzero is the equivalent. The original paper is Brent (1973), "Algorithms for Minimization Without Derivatives." For root-finding without an analytical derivative, Brent is the safe default.
What if my function has complex roots?
Real-valued bisection and Newton can't find them. For polynomials, np.roots and MATLAB's roots return complex roots automatically because they work on the companion matrix. For general functions, Newton's method extended to the complex plane (Müller's method, or just Newton with complex arithmetic) handles them, but you need a complex starting guess. Most engineering and statistics root-finding stays in the reals because the application domain doesn't admit complex solutions; if you're solving for a physical quantity and getting complex roots, the model is the problem, not the solver.
Tolerance way below 10⁻¹⁴, will my answer be more accurate?
No. Double-precision (float64) has about 15-16 significant digits of precision. Any tolerance tighter than ~10⁻¹⁴ is below the noise floor of the arithmetic itself. The iteration may oscillate at machine precision without ever "converging" to that tolerance, and the solver reports failure on what should have been a successful run. For arbitrary precision work, switch to Python's mpmath or Mathematica, which can hold hundreds of digits at the cost of much slower computation.
Related Math & Statistics Tools
Calculus Calculator
Compute derivatives and integrals of functions
Regression Calculator
Fit linear and polynomial regression models to data
Linear Algebra Helper
Compute determinant, rank, trace, and eigenvalues
Matrix Operations
Perform matrix addition, multiplication, and transpose
Descriptive Statistics
Calculate mean, median, standard deviation, and more
Logistic Regression Demo
Explore binary classification with sigmoid function