1
$\begingroup$

I need to write a while or do loop to perform the iteration $x_{n+1}=Cos(x_n)$ with initial value $x_0=1$ and stops when the absolute value of the difference between two consecutive iterations is $|x_{n+1}-x_n|<\epsilon$ , where $\epsilon =10^{-16}$. Finally print the final value $x_{n+1}$, displaying 16 decimal digits.

I can define the relevant function and variables, but don't know exactly how to execute the while loop to return me the required solution, here is my code:

epsilon = 10^{-6}

h[n] = Cos[n]

h[n + 1] = Cos[h[n]]

h[0] = 1

While[Abs[h[n + 1] - h[n]] < epsilon,
 n = n + 1;
 h[n + 1] = Cos[h[n]];
 Print[h[n]]
 ]

I know other programming languages, but working with mathematica and its function layouts is a bit hard until I get used to it. If someone can help me how to set up this function with a while or do loop, and explain me its procedure, I will appreciate their effort and time.

$\endgroup$
7
  • 1
    $\begingroup$ Study this x=1;While[Abs[Cos[x]-x]>=epsilon,x=Cos[x]];N[x,16] and see if it does what you want. Perhaps include a Print[N[Abs[Cos[x]-x],16]] inside the the loop so you can watch the convergence until you believe you can trust it. $\endgroup$
    – Bill
    Commented Nov 7, 2020 at 2:18
  • 1
    $\begingroup$ Now that fixed point, why not FixedPoint? $\endgroup$ Commented Nov 7, 2020 at 7:26
  • $\begingroup$ I think the definition h[n] = Cos[n] isn't what you want; you only want h[0] = 1 and h[n + 1] = Cos[h[n]]. Otherwise, when given, say, h[3], should mathematica produce Cos[3] (first definition) or Cos[h[2]] (second)? However, the thing is that you don't actually want to use any of these definitions at all! The code inside the while loop is what's setting the value of h[something]; it shouldn't be set outside of that context if you're not going to use it, as it might produce weird behavior. $\endgroup$
    – thorimur
    Commented Nov 7, 2020 at 10:03
  • $\begingroup$ Also note that defining, say, h[5] = Cos[h[4]] stores the value of h[5] as part of its definition for h, while still remembering the prior values. But if you only need the last two values, you can just make a name for the most recent two values, e.g. h and h0, and have the "time of the while loop" implicitly provide your $n$. You can assign them both at once via {h,h0} = {Cos[h],h}. (Note how the value of h0 is thrown away, as it becomes "too old" to be relevant.) You could also eschew the second variable in favor of just the function applied to h0, as suggested in another comment. $\endgroup$
    – thorimur
    Commented Nov 7, 2020 at 10:04
  • 1
    $\begingroup$ Also note that your condition ini the While loop is reversed: as is, it's saying "while the difference is less than epsilon, execute my code". But you want "until the difference is less than epsilon"! I.e., Abs[h-h0] >= epsilon. Also: you currently have epsilon = 10^{-6}. Mathematica generally doesn't accept LaTeX notation; this is saying "10 to the power of the list containing the element -6". You want epsilon = 10^(-6)! $\endgroup$
    – thorimur
    Commented Nov 7, 2020 at 10:10

1 Answer 1

2
$\begingroup$

You don't need to define any functions. You just need to write a While-loop.

It is tempting to write the While-loop to use system floating-point arithmetic for speed, like so:

With[{ϵ = 10.^-16},
  Block[{x = 1., nxt},
    While[True,
      nxt = Cos[x];
      If[Abs[nxt - x] < ϵ, Break[], x = nxt]];
    nxt]]

But this doesn't work because system floating-point arithmetic can't maintain 16 digits of precision over the iteration. To avoid this numerics problem, the While-loop can be written to compute with exact numbers. The final value will be converted to a 16-digit arbitrary precision number.

With[{ϵ = 10^-16},
  Block[{x = 1, nxt},
    While[True,
      nxt = Cos[x];
      If[Abs[nxt - x] < ϵ, Break[], x = nxt]];
  N[nxt, 16]]]

0.7390851332151606

The above can be simplified a little by using an undocumented feature of Break. It returns its argument when given one.

With[{ϵ = 10^-16},
  Block[{x = 1, nxt},
    While[True,
      nxt = Cos[x];
      If[Abs[nxt - x] < ϵ, Break[N[nxt, 16]], x = nxt]]]]

The code editor complains about this use of Break, but the evaluator accepts it and it works fine.

I also feel I should point out that it is better Mathematica practice to use FixedPoint than to write a While-loop.

With[{ϵ = 10^-16},
  N[FixedPoint[Cos, 1, SameTest -> (Abs[#1 - #2] < ϵ &)], 16]]

0.7390851332151606

$\endgroup$

Your Answer

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

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