{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Simple chaotic behavior in non-linear systems\n", "\n", "In the last lecture, we discussed how floating point arithmetic can be subtle: its finite precision leads to the fact that even simple properties of elementary arithmetic, like the associativity of addition, don't hold:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(a + b) + c = 1.0\n", "a + (b + c) = 1.0000000000000002\n" ] } ], "source": [ "a, b, c = 1, 1e-16, 1e-16\n", "print(f\"(a + b) + c = {(a + b) + c}\")\n", "print(f\"a + (b + c) = {a + (b + c)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This behavior can have serious implications in a variety of numerical work scenarios. \n", "\n", "Consider the seemingly trivial problem of evaluating with a computer the\n", "expression\n", "\n", "$$f(x) = r x (1-x)$$\n", "\n", "where $r$ and $x$ are real numbers with $r \\in [0,4]$ and $x \\in (0,1)$.\n", "This expression can also be written in an algebraically equivalent form:\n", "\n", "$$f_2(x) = rx - rx^2.$$\n", "\n", "We will see, however, that when using a computer these two forms don't\n", "necessarily produce the same answer. Computers can not represent the\n", "real numbers (a mathematical abstraction with infinite precision) but\n", "instead must use finite-precision numbers that can fit in finite memory.\n", "The two expressions above can, therefore, lead to slightly different\n", "answers as the various (algebraically equivalent) operations are carried\n", "by the computer.\n", "\n", "First a look at a few simple tests:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f1: 0.30399999999999994\n", "f2: 0.3039999999999998\n" ] } ], "source": [ "def f1(x): return r*x*(1-x)\n", "def f2(x): return r*x - r*x**2\n", "\n", "r = 1.9\n", "x = 0.8\n", "print('f1:', f1(x))\n", "print('f2:', f2(x))" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "f1: 0.6239999999999999\n", "f2: 0.6239999999999997\n" ] } ], "source": [ "r = 3.9\n", "x = 0.8\n", "print('f1:', f1(x))\n", "print('f2:', f2(x))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The difference is small but not zero:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "difference: 2.220446049250313e-16\n" ] } ], "source": [ "print('difference:', (f1(x)-f2(x)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More importantly, this difference begins to accumulate as we perform the\n", "same operations over and over. Let's illustrate this behavior by using\n", "the formulas above *iteratively*, that is, by feeding the result of the\n", "evaluation back into the same formula:\n", "\n", "$$x_{n+1} = f(x_n), n=0,1, \\ldots$$\n", "\n", "We can experiment with different values of $r$ and different starting\n", "points $x_0$ to observe the different results. We will simply build a\n", "python list that contains the results of three different (algebraically\n", "equivalent) forms of evaluating the above expression.\n", "\n", "
Exercise
\n", "\n", "Build a little script that computes the iteration of $f(x)$ using three different ways of writing the expression. Store your results and plot them using the `plt.plot()` function (the solution follows).
\n", "\n", "