I have tried to implement a bisection method for finding roots using SetAttributes[BisectionItt, HoldAll] and then SetAttributes[BisectionItt, First]; both to no avail. I have tried reading up on the issue, but I can't seem to implement anything that works.

I want a function implementing the following form:

Bisection[left initial, right initial, function, number of iterations] -> estimate of root

Here is my code:

Bisection[a0_, b0_, function_, itt_] :=
    a = N[a0];
    b = N[b0];
    m = (a+b)/2;
    If[function[m] > 0, a = m, b = m];
    If[itt  < 0, 
      Return[Bisection[a, b, function, itt--]]];]

f[x_] := x^3 - 5 x + 1;
Bisection[0, 1, f, 7]

I believe that this a pass by value/reference issue. I would be very grateful if someone could show me a working example.

    – Chris K
    Oct 22 '18 at 11:34
  • $\begingroup$ Related: mathematica.stackexchange.com/questions/69771/… $\endgroup$
    – Michael E2
    Oct 23 '18 at 10:49

Running your code produces the error Decrement::rvalue: 7 is not a variable with a value, so its value cannot be changed. That made me look at the itt-- part. Using -- attempts to change the variable itt, which can't be done here since it's an argument of your function. All you need to do is replace itt-- by itt-1 and your code works fine.

P.S., if a,b,m are local variables, you can put them in the {} after Module[.


Many ideas imported from procedural programming languages don't fit Mathematica. Mathematica is an expression rewriting language. If I have a definition:

foo[x_]:= an expression

That means "when you see foo[something], evaluate something and then replace every x in an expression with the result and then evaluate an expression". So, if you evaluate foo[1], all instances of x in an expression are replaced by 1 before evaluating an expression. Here, x is not a variable, but the name of a pattern that matches an argument.

Your Module isn't needed. Module is a symbol localization construct, but you are giving it an empty list of symbols to localize. The only thing it's doing is giving Return something to return from, but you don't need Return. Return doesn't do what you think it does. Don't use it until you understand what it does. Then you'll almost never use it.


My favorite way to implement the bisection method is as follows.

      bisectStep[f_, {aStart_, bStart_}] :=
            {a = N[Min[aStart, bStart]], b = N[Max[aStart, bStart]], fa, c, fc},
            fa = f[a];
            c = Mean[{a, b}]; fc = f[c];
            If[Sign[fa] != Sign[fc], b = c, a = c];
            {a, b}

      bisect[f_, a_, b_, \[Delta]_] := 
         Mean /@ NestWhileList[bisectStep[f, #] &, {1, 2}, (Subtract @@ Reverse[#] > \[Delta]) &]

It is used as follows:

      bisect[f, 1, 2, 0.00001]

Note that:

  • the output consists of the midpoints of the successive intervals; and
  • the stopping test is closeness of successive $x$-values (and not smallness of magnitude of function values).

If you want to see more than the default number of decimal places in the output, use NumberForm, e.g.:

      bisect[f, 1, 2, 0.00001] // NumberForm[#, 10] &
