2
$\begingroup$

For an assignment, I have to implement Newton's method using Module and a For loop. So far, I have

newtMethod[guess_, fun_] :=
 ( Module[{k, x0, x1},
   x0 = guess;
   For[k = 1,
    Abs[x1 - x0] >= .0001,
    k = k + 1,
    x1 = (x0 - fun[x0]/fun'[x0]);
    If[Abs[x1 - x0] < 0, x0 = x1, x1 = x1];
    x1]; Print[x1]])

When I run this, a strange message appears.

f[x_] := Sin[E^x];
newtMethod[2.5, f]
x1$5709

If I remove the Print[x1] part of the code, there's NO output entirely. What am I doing wrong here? Is there any meaning to the weird output? I think my error has to do with what I included in the For loop and what I defined x1 to be, but I'm not sure. Any tips?

$\endgroup$
2
  • $\begingroup$ Nest, NestWhile or FixedPoint should be better choices. $\endgroup$ Commented Nov 19, 2020 at 17:19
  • 1
    $\begingroup$ Also you don't need the Print at all. Mathematica expressions like Module/Block return their final result, so you'll get x1 from that, no printing necessary $\endgroup$
    – b3m2a1
    Commented Nov 19, 2020 at 17:22

5 Answers 5

8
$\begingroup$

The main reason is that x1 is not assigned a value before entering the for loop:

newtMethod[guess_, 
  fun_] := (Module[{k, x0, x1}, x0 = guess; 
   x1 = (x0 - fun[x0]/fun'[x0]);
   For[k = 1, Abs[x1 - x0] < .0001, k = k + 1, 
    x1 = (x0 - fun[x0]/fun'[x0]);
    If[Abs[x1 - x0] < 0, x0 = x1, x1 = x1];
    x1]; Print[x1]])

f[x_] := Sin[E^x];
newtMethod[2.5, f]
FindRoot[Sin[E^x] == 0, {x, 2.5}]
$\endgroup$
8
$\begingroup$

Worth putting it out there that the For loop is not your friend. This does the same

newtonOneLine // Clear
newtonOneLine[fun_, x0_, tol_ : .0001, maxIters_ : 1000] :=
 
 Module[{fp = fun'},
  FixedPoint[# - (fun[#]/fp[#]) &, 
   x0, 
   SameTest -> (Abs[#1 - #2] < tol &)
   ]
  ]
$\endgroup$
7
$\begingroup$

Well, since interest in Newton's method never seems to fade on this site, here's a Iterator[] based approach:

Needs@"GeneralUtilities`";

(*
 * fixedPointIterator
 *   Returns x = f[x] unless x == f[x]
 *)
ClearAll[fixedPointIterator];
fixedPointIterator[f_, x0_, sameQ_ : SameQ] := 
 GeneralUtilities`NewIterator[
  fixedPointIterator,  (* name *)
  {x = x0},            (* state variables *)
  With[{xx = f[x]},    (* iterator action *)
   If[sameQ[x, xx],
    GeneralUtilities`IteratorExhausted,
    x = xx]]
  ]

newtonIterator[f_, x0_, sameQ_ : Equal] :=
 fixedPointIterator[# - f[#]/f'[#] &, x0, sameQ]

ff[x_] := Sin[E^x];
rootIt = newtonIterator[ff, 2.5];

ReadList[rootIt, 100 (* max iterations *)]
ff[%] (* check *)
(*
  {2.53316, 2.53103, 2.53102, 2.53102}
  {0.0268055, 0.0000221047, 1.94364*10^-11, -4.89859*10^-16}
*)

Note: Equal compares real numbers with tolerance (equal up to their last seven bits). SameQ compares real numbers with smaller tolerance (equal up to their last bit). Pass a custom comparator to use a different tolerance.

Also, the overhead of Iterator[] makes it fairly slow compared to, say, FixedPoint[].

$\endgroup$
4
  • 1
    $\begingroup$ Never heard of this! Looks like mathematica.stackexchange.com/questions/135916/… is a good source for more info if anyone else is curious. $\endgroup$
    – Chris K
    Commented Nov 20, 2020 at 2:04
  • $\begingroup$ Iterator can, it seems, be used in compiled stuff too, which might be a useful way to go with this $\endgroup$
    – b3m2a1
    Commented Nov 20, 2020 at 4:47
  • $\begingroup$ @b3m2a1 Compile or FunctionCompile? I can't get it to work with either one. I'm not very good at FunctionCompile, tho. $\endgroup$
    – Michael E2
    Commented Nov 20, 2020 at 14:43
  • $\begingroup$ @MichaelE2 ah looks like I just got confused by the existence of Compile`SetIterate and Compile`IteratorCount in Compile`CompilerFunctions[] // Sort $\endgroup$
    – b3m2a1
    Commented Nov 20, 2020 at 20:32
5
$\begingroup$

First, let me just cleaning up the orignal code and the answer from https://mathematica.stackexchange.com/a/234969/148:

newtMethod[guess_, fun_] := 
  Module[{k, x0 = guess, x1},
  x1 = x0 - fun[x0]/fun'[x0];
  For[k = 1, Abs[x1 - x0] < .0001, k++, 
   x1 = x0 - fun[x0]/fun'[x0];
   If[Abs[x1 - x0] < 0, x0 = x1, x1 = x1]];
  x1]

This returns the most recent value of x1 rather than printing it; initializes x0 within the first argument to Module; and elides superfluous parentheses.

Note 1: For serious work, you'd want to use a fixed limit on the number of steps, either through hard-coding into the body of newtMethod or as an additional, argument to newtMethod. (For that matter, it would be more generally useful to make the tolerance .0001 another argument to newtMethod.)

Note 2: It is dangerous to use as stopping criterion just closeness of successive x-values to each other, and essential for some functions &meash; those that are fairly flat — to use in addition closeness of the value of f at the current x to the desired value 0.

$\endgroup$
1
$\begingroup$

Not at all sure what is going on here.

  1. The For loop test seems backwards. In the test example the logic test is initially not true so the loop isn't executed.

  2. In the If statement the test for Abs[anything]<0 doesn't seem to make sense?

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.