2
$\begingroup$

I am trying to program Newton's Method in Mathematica to compute the roots of $f(x)=x^3-6x^2+11x-6$ using the Do command but my code gives a General::ivar error and doesn't work and I can't figure out what is wrong with it:

f[x_] := x^3 - 6*x^2 + 11*x - 6
g[x_] := D[f[x], x]
a[0] = 0;
Do[a[n + 1] = a[n] - N[f[a[n]]/g[a[n]]], {n, 0, 100}]

Table[a[n], {n, 0, 100}]

Can you explain what's wrong with it?

$\endgroup$
1

2 Answers 2

4
$\begingroup$

This would be more idiomatic:

Clear[f, g, newtonIteration]

f[x_] := x^3 - 6*x^2 + 11*x - 6
g[x_] = D[f[x], x];

newtonIteration[previousEstimate_] :=
 previousEstimate - f[previousEstimate]/g[previousEstimate]

FixedPointList[
  newtonIteration,
  0.  (* starting value *),
  100 (* max number of iterations *)
]

(* Out: {0., 0.545455, 0.848953, 0.974674, 0.999092, 0.999999, 1., 1., 1.} *)

Even shorter, with pure functions:

FixedPointList[# - f[#]/g[#] &, 0., 100]

The third argument of FixedPointList (the 100) is there to as a fail-safe, to stop runaway iterations that do not converge after 100 steps.

You want to use Set (=) instead of SetDelayed (:=) here to define the derivative g, so it is calculated symbolically and stored in g, and then numerical values of x are substituted as needed. On the other hand, using SetDelayed (:=) forces the re-calculation of the derivative at each step. In particular, this means that x will have already been assigned a numerical value at that point. and it will no longer be a valid variable for differentiation. This was the origin of the error in your original code.

$\endgroup$
1
$\begingroup$

To answer your question:

Notice the change in definition of f[x], g[x]

Clear[f, g, a]
f[x_] = x^3 - 6*x^2 + 11*x - 6
g[x_] = D[f[x], x]
a[0] = 0;
Do[a[n + 1] = a[n] - N[f[a[n]]/g[a[n]]], {n, 0, 7}]
Table[a[n], {n, 0, 7}]

{0, 0.545455, 0.848953, 0.974674, 0.999092, 0.999999, 1., 1.}


Save your work before you run such loops.

To help you understand it further:

Clear[f, g, a]
f[x_] = x^3 - 6*x^2 + 11*x - 6
g[x_] = D[f[x], x]
a[0] = 0;
Do[a[n + 1] = a[n] - N[f[a[n]]/g[a[n]]];
 Echo[a[n] , "a[" <> ToString@n <> "] = "];
 Pause[1];
 , {n, 0, 10}]

Now you can try with the SetDelayed := and see the difference.

Keep the Pause in there or it would be hard to abort evaluation in cases where it misbehaves.

$\endgroup$