|
363 | 363 | \end{equation}%
|
364 | 364 | %
|
365 | 365 | We can roughly imagine that the algorithm works as follows:
|
366 |
| -If $x_i$ was too big~($x_i>\sqrt{a}$), then~$\frac{a}{x_i}<\sqrt{a}<x_i$. |
367 |
| -If $x_i$ was too small~($x_i<\sqrt{a}$), then $\frac{a}{x_i}>\sqrt{a}>x_i$. |
368 |
| -By computing the average of~$x_i$ and~$\frac{a}{x_i}$ as the next guess, we will approach~$\sqrt{a}$. |
| 366 | +If $x_i$ was too big, i.e., $x_i>\sqrt{a}$, then~$\frac{a}{x_i}<\sqrt{a}<x_i$. |
| 367 | +If $x_i$ was too small, i.e., $x_i<\sqrt{a}$, then $\frac{a}{x_i}>\sqrt{a}>x_i$. |
| 368 | +By computing the average of~$x_i$ and~$\frac{a}{x_i}$ as the next guess, we hope to approach~$\sqrt{a}$. |
369 | 369 | If $x_i=\sqrt{a}$, then $\frac{a}{x_i}=\sqrt{a}$ by definition and~$x_{i+1}=x_i$.
|
| 370 | +Showing that this actually works and that the error gets smaller over time is more complicated~\cite{S2011NA2}. |
370 | 371 |
|
371 | 372 | If we want to implement this algorithm, we will naturally need a loop of some sort.
|
372 | 373 | Clearly, we perform the same computation again and again.
|
373 | 374 | However, a \pythonil{for}~loop will not do:
|
374 |
| -We do not know the number of steps we need in advance. |
| 375 | +We do not know the number of steps that we will need in advance. |
375 | 376 | Of course, we could try to pick a very very huge number and then \pythonil{break} the loop when the guesses converg {\dots} but that is just ugly.
|
376 | 377 | The \pythonilIdx{while} comes to rescue:%
|
377 | 378 | %
|
|
395 | 396 |
|
396 | 397 | We begin the program with an outer \pythonil{for} loop that iterates a variable~\pythonil{number} over the \pythonil{float} values \pythonil{0.5}, \pythonil{2.0}, and~\pythonil{3.0}.
|
397 | 398 | We want to apply the algorithm to each of these values.
|
398 |
| -We use two variables~\pythonil{guess} be the current guess of what $\sqrt{\pythonil{number}}$ could be and \pythonil{old_guess} be the previous guess.% |
| 399 | +We use two variables~\pythonil{guess} be the current guess of what $\sqrt{\pythonil{number}}$ could be and \pythonil{old_guess} be the previous guess. |
| 400 | + |
| 401 | +We initialize \pythonil{guess} with \pythonil{1.0} and \pythonil{old_guess} with a different value, say~\pythonil{0.0}. |
| 402 | +Our \pythonilIdx{while} loop should keep iterating as long as~\pythonil{guess != old_guess}. |
| 403 | +Of course, if we could represent real numbers at infinite precision, we would never reach \pythonil{guess == old_guess} for any \pythonil{number} with an irrational square root. |
| 404 | +However, the \pythonil{float} datatype has limited precision (see \cref{sec:howFloatingPointNumbersWork}). |
| 405 | +Therefore, at least in our examples, \pythonil{guess != old_guess} indeed eventually becomes~\pythonilIdx{False}.% |
399 | 406 | %
|
400 |
| -\begin{sloppypar}% |
401 |
| -We initialize \pythonil{guess} with \pythonil{1.0}. |
402 |
| -Our \pythonilIdx{while} loop should keep iterating as long as \pythonil{guess != old_guess}. |
403 |
| -This only works because the \pythonil{float} datatype has limited precision which we will eventually exhaust, see \cref{sec:howFloatingPointNumbersWork}. |
404 |
| -Anyway, the loop condition necessitates us to store some value different from~\pythonil{1.0} in \pythonil{old_guess} initially (and we pick~\pythonil{0.0}). |
405 |
| -In the loop, first the current guess becomes the old guess via \pythonil{old_guess = guess}. |
406 |
| -Then we update the guess as in \cref{eq:heronGuessUpdate}, by setting \pythonil{guess = 0.5 * (guess + number / guess)}.% |
407 |
| -\end{sloppypar}% |
| 407 | +\bestPractice{noFloatEqualAsCondition}{% |
| 408 | +Do not use (un)equality comparisons of \pythonils{float} as loop termination criteria, as they may lead to endless loops. % |
| 409 | +There can always be inputs that cause endless oscillations between values or the appearance of \pythonilIdx{nan} values (see \cref{sec:float:special}).% |
| 410 | +}% |
408 | 411 | %
|
| 412 | +The only reason why we did it here is that it looks nice and is easy to read as a functional and yet brief example for a \pythonilIdx{while} loop. |
| 413 | +Anyway, the loop condition necessitates us to store some value different from~\pythonil{1.0} in \pythonil{old_guess} initially (and we picked~\pythonil{0.0}). |
| 414 | +In the loop, first the current guess becomes the old guess via \pythonil{old_guess = guess}. |
| 415 | +Then we update the guess as specified in \cref{eq:heronGuessUpdate}, by setting \pythonil{guess = 0.5 * (guess + number / guess)}. |
| 416 | + |
409 | 417 | Finally, we print the result of the computation, and for the sake of comparison, we also print the output of the \pythonilIdx{sqrt} function of the \pythonilIdx{math} module.
|
410 |
| -As you can see, our algorithm delivers exactly the same result. |
| 418 | +As you can see, our algorithm delivers almost the same result. |
| 419 | +It works quite well, at very high precision. |
411 | 420 | Also, notice how we used the Unicode escape method from \cref{sec:unicodeChars} to represent the characters~$\sqrt{\cdot}$ and~$\approx$ as \textil{\\u221A} and \textil{\\u2248} to get them printed on the console.%
|
412 | 421 | %
|
413 | 422 | \FloatBarrier%
|
|
0 commit comments