Search code examples
matlabfunctionwhile-loopbisectionconvergence

Bisection doesn't return a value


The function below, bisection, is supposed to find a root given three inputs: a function f, and an interval defined using the two parameters a and b. The intention is that the value of a and b are changed within the function to approach a common point, as long as their signs are different.

When I call my function like this:

bisection( @(x)x-1 ,-2,3)

no output is returned. What am I doing wrong?

function X = bisection(f,a,b)

if ge((f(a)*f(b)),0)

    disp('Wrong')

    return;
end

X = (a+b)/2;
while abs(X)>0.01

    if f(X)*f(a)>0
        X=a;
    else 
        X=b;
    end
end

Solution

  • Enter the Infinite!

    Well done! You've written your first (and not last, believe me) infinite loop. The problem is threefold. Firstly your stop condition was abs(X) and should have been abs(f(X)) - you don't care for X to be zero, you want f(X) to be zeros. Secondly you don't update your your X correctly so your break condition is never hit (unless you are lucky to give this function symmetrical a,b bounds around the zero of the function). You could see this easily by adding a line like disp(f(X)); pause(0.5); somewhere in the while-loop.

    In general try to avoid infinite loops with some explicit stop condition. In my code below I've put in the interaction limit past which the algorithm will just stop (it would be more elegant to catch that condition and warn the user of hitting the iteration limit...).

    function x0 = bisection(f,a,b)
    assert(f(a)*f(b)<0,'Invalid f(x) range. f(a)*f(b) >= 0');
    
    tol = 0.00001; % Tolerance
    iter_limit = 10000; % Limit of number of iterations
    
    iter = 0;
    x0 = (a+b)/2; % Midpoint
    while abs(f(x0)) > tol && iter < iter_limit
        if f(x0)*f(a) > 0
            a = x0; % Zero to the right of the midpoint
        else 
            b = x0; % Zero to the left
        end
    
        x0 = (a+b)/2; % Recalculate midpoint
        iter = iter + 1;
    end
    end
    

    This should work no problem with

    f = @(x)x-1;
    bisection(f,-2,3);
    

    I get something like 0.999992370... which is within specified tolerance from the actual answer (1).