1
$\begingroup$

I'm trying to create a function using Nest, which will use Newton's method to find the root of the passed function (or even the passed expression).

I've got this, which won't work obviously.

newtonsMethod[fn_, x0_, n_] := Nest[# - fn[#]/fn'[#] &, x0, n]

I'm hoping to be able to call the function like so:

g[x_]:=x^2-2;
newtonsMethod[g[x], 1, 6]

Or even better, it would be nice to avoid the function to pass, and just pass the expression:

newtonsMethod[x^2-2, 1, 6]

For some simpler examples of passing functions or expressions as arguments, I'm able to use ReplaceAll within the function to get things to work, but it seems I'm unable to do so here.

$\endgroup$
3
$\begingroup$

FindRoot asks the user to say what the variable is. Proceeding in that way, we might use

SetAttributes[newtonsMethod, HoldAll]
newtonsMethod[fn_, {x_, x0_}, n_] := Module[{f},
  f[x_] := fn;
  Nest[# - f[#]/f'[#] &, x0, n]
  ]

newtonsMethod[y^2 - 2, {y, 1}, 10] // N

1.41421

As a comparison,

FindRoot[x^2 - 2, {x, 1}]

{x -> 1.41421}

Note: Mathematica throws an error when defining newtonsMethod – but it still works. I think this is one of those cases where Mathematica throws an error for something that is technically correct, just because it's usually a mistake. In this case it is motivated, however.

The HoldAll attribute allows us to use assigned variables in our expression. So we could do for example:

x = 10;
newtonsMethod[x^2 - 2, {x, 1}, 10] // N

1.41421

This is a feature that FindRoot also has.

$\endgroup$
2
$\begingroup$

If you want to pass the expression in directly, you could do something like the following:

eval[fn_, x_] := fn /. Thread[Variables[fn] -> x]

newtonsMethod[fn_, x0_, n_] := Nest[# - eval[fn, #]/eval[D[fn, Variables[fn]], #] &, x0, n]

newtonsMethod[x^2 - 2, 1, 6]

1572584048032918633353217/1111984844349868137938112

If I were in your shoes, I would want to pass the function:

ClearAll @ newtonsMethod

newtonsMethod[fn_, x0_, n_] := Nest[# - fn[#]/fn'[#]&, x0, n]

g[x_] := x^2 - 2

newtonsMethod[g, 1, 6]

1572584048032918633353217/1111984844349868137938112

$\endgroup$
2
$\begingroup$

If you want to be really careful, you should properly localize the variables and add syntax checking to your function. Here is a way to do this:

ClearAll[newtonsMethod]
SetAttributes[newtonsMethod, HoldAll];
SyntaxInformation[
   newtonsMethod] = {"LocalVariables" -> {"FindRoot", {2, 2}}, 
   "ArgumentsPattern" -> {_, _, OptionsPattern[]}};
newtonsMethod[expr_, {x_, x0_, n_}] := 
 Module[{f, xSymbol, xLocal},
  xSymbol = Unevaluated[x] /. x1_ :> HoldPattern[x1];
  f[xLocal_] := Unevaluated[expr] /. xSymbol :> xLocal;
  Nest[# - f[#]/f'[#] &, x0, n]]

newtonsMethod[x^2 - 2, {x, 1., 10}]

1.41421

The feature I added in this answer is that the syntax is just like it is in FindRoot, including the fact that x is treated as a local variable even if it has a global value. You can try this by setting e.g. x = 0 and then calling newtonsMethod again. Without the use of Unevaluated and HoldPattern to replace the global variable in the expression, you'd have to manually clear x before calling the function with the expression x^2 - 2.

Since FindRoot returns a replacement rule of the form {x->1.41421}, it can't be immune against global assignments to x: With a global setting x = 0, you would get

FindRoot[x^2 - 2, {x, 1}]

{0 -> 1.41421}

Here, the internal workings of FindRoot do in fact localize x so that the correct solution value is found (1.41421), but then x is replaced by 0 because the output {x -> 1.41421} is evaluated.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.