Suites récurrentes et chaos Grand Oral · mathématiques, physique-chimie, NSI, SES, SVT Un support de connaissances pour construire sa propre question

← Tous les textes du Grand Oral

MathsPCNSISESSVT

Une formule toute simple, $u_{n+1} = r\,u_n(1-u_n)$, appliquée encore et encore. Selon la valeur du nombre $r$, la suite se stabilise, oscille sagement, ou devient si désordonnée qu'aucun calcul ne permet de prévoir ses valeurs à long terme, bien qu'elle soit entièrement déterminée par sa formule. C'est le chaos : un comportement imprévisible produit par une règle parfaitement déterministe. Ce texte part de la construction du graphique d'une suite récurrente, montre l'apparition du chaos, puis le retrouve en physique, en informatique, en météorologie et en économie. À chacun d'y choisir une direction et d'y construire sa question.

Sommaire
  1. Construire le graphique d'une suite récurrente
  2. La suite logistique : de l'ordre au chaos
  3. Déterministe ne veut pas dire prévisible
  4. L'histoire de Lorenz et le papillon
  5. En physique : quand un petit écart change tout
  6. En informatique : les calculs de la machine
  7. En économie et en biologie
  8. Programmer et observer
  9. Des directions pour construire sa question
Construire le graphique d'une suite récurrente

Une suite est définie par récurrence lorsqu'on donne son premier terme $u_0$ et une fonction $f$ telle que $u_{n+1} = f(u_n)$ pour tout $n$. On peut représenter ses termes sur l'axe des abscisses sans calculer, grâce à la courbe de $f$ et à la droite d'équation $y = x$. La construction se fait étape par étape.

  1. Tracer la courbe de $f$ et la droite $\Delta$ d'équation $y = x$.
  2. Placer $u_0$ sur l'axe des abscisses.
  3. Monter (ou descendre) verticalement jusqu'à la courbe : le point atteint a pour ordonnée $f(u_0) = u_1$.
  4. Se déplacer horizontalement jusqu'à la droite $\Delta$ : le point atteint a pour coordonnées $(u_1\,;u_1)$, donc son abscisse est $u_1$. On a ainsi « reporté » $u_1$ de l'axe des ordonnées vers l'axe des abscisses.
  5. Recommencer depuis $u_1$ : verticalement jusqu'à la courbe (ordonnée $u_2$), horizontalement jusqu'à $\Delta$, et ainsi de suite.

Le chemin obtenu, fait de segments verticaux et horizontaux, s'appelle un diagramme en escalier ou en « toile d'araignée ». Il permet de lire le comportement de la suite.

var r = board.create('slider', [[0.05, 1.28], [0.55, 1.28], [2.5, 2.8, 4]], {name: 'r', snapWidth: 0.01, digits: 2}); var n = board.create('slider', [[0.05, 1.17], [0.55, 1.17], [1, 3, 60]], {name: 'étapes', snapWidth: 1, digits: 0}); var u0 = board.create('glider', [0.2, 0, board.defaultAxes.x], {name: 'u₀', size: 3, color: '#000'}); board.create('functiongraph', [function (x) { return r.Value()*x*(1-x); }, 0, 1], {strokeColor: '#1565c0', strokeWidth: 2}); board.create('functiongraph', [function (x) { return x; }, 0, 1], {strokeColor: '#888', strokeWidth: 1}); var c = board.create('curve', [[0], [0]], {strokeColor: '#d32f2f', strokeWidth: 1.2}); c.updateDataArray = function () { var u = Math.min(1, Math.max(0, u0.X())), k, v; this.dataX = [u]; this.dataY = [0]; for (k = 0; k < Math.round(n.Value()); k++) { v = r.Value()*u*(1-u); this.dataX.push(u, v); this.dataY.push(v, v); u = v; } }; board.update(); Le diagramme en toile d'araignée de $u_{n+1} = r\,u_n(1-u_n)$. On peut changer $r$, le nombre d'étapes et faire glisser $u_0$ sur l'axe.
La suite logistique : de l'ordre au chaos

La suite $u_{n+1} = r\,u_n(1-u_n)$, avec $u_0$ entre $0$ et $1$ et $r$ entre $0$ et $4$, vient de la biologie. En 1838, le mathématicien belge Pierre-François Verhulst propose un modèle de croissance d'une population limitée par ses ressources : $u_n$ représente la population à l'année $n$, rapportée au maximum que le milieu peut nourrir. Le facteur $r\,u_n$ traduit la reproduction, le facteur $1 - u_n$ la concurrence pour la nourriture. En 1976, l'écologue Robert May publie dans la revue Nature un article qui révèle à quel point ce modèle si simple peut se comporter de façon compliquée. Avec $u_0 = 0{,}2$ :

$r$comportement à long terme
$2{,}8$converge vers le point fixe $1 - \frac{1}{r} \approx 0{,}643$
$3{,}2$oscille entre $0{,}513$ et $0{,}799$ (période $2$)
$3{,}5$répète $0{,}501$ ; $0{,}875$ ; $0{,}383$ ; $0{,}827$ (période $4$)
$3{,}9$aucune régularité : chaos
Un petit changement de départ, de grosses répercussions

Pour $r = 3{,}9$, comparons deux suites qui partent de $u_0 = 0{,}2$ et de $u_0 = 0{,}2001$ : l'écart initial est d'un dix-millième. Au rang $10$, l'écart vaut encore $0{,}003$. Mais au rang $16$, il dépasse $0{,}1$, et au rang $20$, une suite vaut $0{,}29$ et l'autre $0{,}90$ : elles n'ont plus rien à voir. Avec $r = 2{,}8$, au contraire, les deux suites convergent vers le même point fixe et leur écart au rang $40$ est inférieur à $10^{-8}$.

var r = board.create('slider', [[2, 1.12], [22, 1.12], [2.8, 3.9, 4]], {name: 'r', snapWidth: 0.01, digits: 2}); function suite(u0, couleur) { var c = board.create('curve', [[0], [0]], {strokeColor: couleur, strokeWidth: 1.5}); c.updateDataArray = function () { var u = u0, k; this.dataX = [0]; this.dataY = [u]; for (k = 1; k <= 40; k++) { u = r.Value()*u*(1-u); this.dataX.push(k); this.dataY.push(u); } }; } suite(0.2, '#1565c0'); suite(0.2001, '#d32f2f'); board.update(); Les termes $u_0$ à $u_{40}$ pour $u_0 = 0{,}2$ (bleu) et $u_0 = 0{,}2001$ (rouge). Pour $r = 3{,}9$, les deux suites se séparent vers le rang $15$ ; en diminuant $r$, elles restent confondues.
Un petit changement du paramètre, un tout autre comportement

La sensibilité ne porte pas seulement sur le point de départ. Pour $r = 3{,}82$, la suite est chaotique ; pour $r = 3{,}83$, soit un changement d'un centième, elle devient parfaitement régulière et répète indéfiniment trois valeurs, environ $0{,}156$ ; $0{,}505$ ; $0{,}957$.

function suite(r, couleur) { var u = 0.5, k, X = [], Y = []; for (k = 0; k < 300; k++) { u = r*u*(1-u); } for (k = 0; k <= 40; k++) { X.push(k); Y.push(u); u = r*u*(1-u); } board.create('curve', [X, Y], {strokeColor: couleur, strokeWidth: 1.5}); } suite(3.82, '#d32f2f'); suite(3.83, '#1565c0'); Quarante termes de la suite, une fois l'état stable atteint, pour $r = 3{,}82$ (rouge, chaotique) et $r = 3{,}83$ (bleu, période $3$).
Le diagramme de bifurcation

Pour avoir une vue d'ensemble, on représente, pour chaque valeur de $r$, les valeurs prises par la suite une fois l'état stable atteint. Jusqu'à $r = 3$, un seul point : la suite converge. En $r = 3$, la courbe se dédouble : la suite oscille entre deux valeurs. En $r = 1 + \sqrt6 \approx 3{,}449$, chaque branche se dédouble à nouveau (période $4$), puis vers $3{,}544$ (période $8$), et ainsi de suite, de plus en plus vite. Ces doublements de période s'accumulent vers $r \approx 3{,}5699$, au-delà duquel le chaos apparaît, entrecoupé de « fenêtres » régulières, comme celle de période $3$ qui s'ouvre en $r = 1 + \sqrt8 \approx 3{,}828$.

var X = [], Y = [], r, u, k; for (r = 2.8; r <= 4; r += 0.004) { u = 0.5; for (k = 0; k < 300; k++) { u = r*u*(1-u); } for (k = 0; k < 80; k++) { u = r*u*(1-u); X.push(r, r + 0.0025, NaN); Y.push(u, u, NaN); } } board.create('curve', [X, Y], {strokeColor: '#283593', strokeWidth: 1.5}); Le diagramme de bifurcation de la suite logistique : en abscisse $r$, en ordonnée les valeurs prises à long terme.

En 1975, le physicien Mitchell Feigenbaum découvre que les écarts entre deux doublements successifs diminuent dans un rapport qui tend vers $4{,}669\ldots$, et que ce nombre est le même pour toute une famille de suites : c'est une constante universelle, comme $\pi$. La même année, les mathématiciens Tien-Yien Li et James Yorke démontrent un théorème au titre célèbre, « Période trois implique chaos ».

Déterministe ne veut pas dire prévisible

Au début du XIXᵉ siècle, Pierre-Simon de Laplace exprime l'idéal d'une science capable de tout prévoir :

Une intelligence qui, pour un instant donné, connaîtrait toutes les forces dont la nature est animée et la situation respective des êtres qui la composent […] embrasserait dans la même formule les mouvements des plus grands corps de l'univers et ceux du plus léger atome ; rien ne serait incertain pour elle, et l'avenir, comme le passé, serait présent à ses yeux. (Essai philosophique sur les probabilités, 1814)

Le chaos ne contredit pas le déterminisme : la suite logistique est entièrement déterminée par $u_0$ et $r$. Ce qu'il remet en cause, c'est la possibilité de prévoir, car on ne connaît jamais les conditions initiales exactement. On parle de sensibilité aux conditions initiales : deux états de départ très proches conduisent à des évolutions qui finissent par n'avoir plus rien de commun.

Pour $r = 4$, on peut le mesurer : l'écart entre deux suites voisines est, en moyenne, multiplié par $2$ à chaque étape. Une erreur de $10^{-6}$ au départ devient de l'ordre de $1$ après une vingtaine d'étapes ($2^{20} \approx 10^6$). Pour prévoir une étape de plus, il faut connaître le départ deux fois plus précisément ; pour en prévoir dix de plus, mille fois plus précisément. Il existe donc un horizon de prévisibilité, au-delà duquel aucun progrès raisonnable des mesures ne permet de voir.

Poincaré et le problème des trois corps

Henri Poincaré découvre ce phénomène bien avant le mot « chaos ». En 1889, il remporte le prix offert par le roi Oscar II de Suède sur la stabilité du système solaire. En corrigeant une erreur de son mémoire, publié en 1890, il comprend que le mouvement de trois corps qui s'attirent, comme le Soleil, la Terre et la Lune, peut être d'une complexité inextricable. Il l'écrit en 1908 :

Une cause très petite, qui nous échappe, détermine un effet considérable que nous ne pouvons pas ne pas voir, et alors nous disons que cet effet est dû au hasard. (Science et méthode, 1908)

L'histoire de Lorenz et le papillon

En 1961, Edward Lorenz, météorologue au MIT, à Cambridge, près de Boston, simule l'atmosphère sur un petit ordinateur, un Royal McBee LGP-30, avec un modèle simplifié de douze variables (températures, vents, pressions). La programmeuse Margaret Hamilton, qui écrira plus tard les logiciels de vol des missions Apollo, l'assiste. Un jour, il veut revoir une partie d'une simulation. Pour gagner du temps, il ne la relance pas depuis le début : il repart du milieu, en tapant à la main des valeurs relevées sur une impression faite pendant le premier calcul. Pendant que la machine, très lente, calcule, il va prendre un café.

À son retour, la nouvelle prévision suit d'abord l'ancienne, puis s'en écarte, jusqu'à ne plus lui ressembler du tout. La machine n'est pas en panne : l'imprimante n'affichait que trois décimales, alors que l'ordinateur en gardait six. Il a tapé $0{,}506$ là où la machine avait en mémoire $0{,}506127$. Un écart d'un dix-millième, bien inférieur à la précision de n'importe quelle mesure météorologique, suffisait à changer complètement le temps prévu à plus long terme.

Lorenz en tire la conséquence en 1963, dans un article intitulé Deterministic Nonperiodic Flow : la prévision du temps à long terme est impossible, non par manque de puissance de calcul, mais par nature. En 1972, il donne une conférence dont le titre deviendra célèbre : « Prévisibilité : le battement d'ailes d'un papillon au Brésil peut-il déclencher une tornade au Texas ? ». L'expression « effet papillon » est née.

On résume souvent l'idée par « un papillon peut provoquer une tornade ». Ce n'est pas ce que dit Lorenz. Un papillon ne fabrique pas l'énergie d'une tornade, et son battement d'ailes est noyé parmi des milliards d'autres perturbations tout aussi minuscules, qui agissent dans tous les sens. Lorenz le précise lui-même dans sa conférence : si un battement d'ailes peut contribuer à déclencher une tornade, il peut tout aussi bien contribuer à l'empêcher.

Le message est ailleurs : comme on ne peut pas connaître l'état de l'atmosphère à l'échelle du papillon, on ne peut pas prévoir le temps au-delà d'un certain horizon, estimé à une quinzaine de jours. Le chaos n'est pas une cause cachée, c'est une limite de la connaissance.

La météorologie moderne en tient compte. Au lieu d'une seule prévision, les centres météorologiques font tourner leur modèle des dizaines de fois à partir d'états de départ légèrement différents : ce sont les prévisions d'ensemble. Si les calculs restent proches, la prévision est fiable ; s'ils divergent, on annonce une probabilité plutôt qu'une certitude.

En physique : quand un petit écart change tout Les chocs successifs

Au billard, une bille qui heurte une autre bille repart dans une direction qui dépend de l'endroit exact du contact. Une petite erreur sur l'angle d'arrivée est multipliée à chaque choc par un facteur qui dépend du rapport entre la distance parcourue et le rayon des billes, souvent supérieur à dix. Après $n$ chocs, l'erreur est donc multipliée par $10^n$ ou plus : une erreur d'un millionième de degré devient, au bout de six ou sept chocs, une erreur de plusieurs degrés. Selon un calcul célèbre du physicien Michael Berry, pour prévoir le neuvième choc d'une bille, il faudrait tenir compte de l'attraction gravitationnelle d'une personne debout près de la table.

Le pendule double

Le pendule simple est régulier : pour de petites oscillations, sa période $T = 2\pi\sqrt{\dfrac{\ell}{g}}$ ne dépend même pas de l'amplitude, et une petite erreur sur la position de départ reste petite. Mais si l'on accroche un second pendule au bout du premier, le mouvement devient chaotique dès que les oscillations sont grandes : deux lâchers presque identiques donnent, au bout de quelques secondes, des mouvements sans rapport. C'est l'une des expériences de chaos les plus simples à réaliser en classe.

La simulation ci-dessous lance deux pendules doubles identiques (deux tiges de $1$ m), lâchés presque de la même position : les angles de départ ne diffèrent que de $0{,}0001$ radian, soit $0{,}006$ degré, un écart invisible à l'œil. Il faut patienter : pendant plusieurs secondes, les deux pendules (bleu et rouge) restent parfaitement superposés, et l'on croit voir un seul pendule. Puis ils se séparent brusquement et n'ont plus rien de commun. Le graphique du bas montre la distance entre les deux masses du bas au fil du temps : presque nulle d'abord, elle explose vers $8$ secondes.

var g = 9.81, L = 1, A, B, t, histT, histE, traceA, traceB; function deriv(s) { var d = s[0] - s[1], den = 3 - Math.cos(2*d); var a1 = (-3*g*Math.sin(s[0]) - g*Math.sin(s[0] - 2*s[1]) - 2*Math.sin(d)*(s[3]*s[3]*L + s[2]*s[2]*L*Math.cos(d))) / (L*den); var a2 = (2*Math.sin(d)*(2*s[2]*s[2]*L + 2*g*Math.cos(s[0]) + s[3]*s[3]*L*Math.cos(d))) / (L*den); return [s[2], s[3], a1, a2]; } function rk4(s, h) { var k1 = deriv(s), i, s2 = [], s3 = [], s4 = []; for (i = 0; i < 4; i++) { s2.push(s[i] + h/2*k1[i]); } var k2 = deriv(s2); for (i = 0; i < 4; i++) { s3.push(s[i] + h/2*k2[i]); } var k3 = deriv(s3); for (i = 0; i < 4; i++) { s4.push(s[i] + h*k3[i]); } var k4 = deriv(s4), r = []; for (i = 0; i < 4; i++) { r.push(s[i] + h/6*(k1[i] + 2*k2[i] + 2*k3[i] + k4[i])); } return r; } function pos(s) { var x1 = L*Math.sin(s[0]), y1 = -L*Math.cos(s[0]); return [x1, y1, x1 + L*Math.sin(s[1]), y1 - L*Math.cos(s[1])]; } function depart() { A = [2, 2, 0, 0]; B = [2, 2.0001, 0, 0]; t = 0; histT = [-2.1]; histE = [-4.2]; traceA = [[], []]; traceB = [[], []]; } depart(); function bras(etat, couleur) { var q = function (i) { return function () { return pos(etat())[i]; }; }; board.create('segment', [[0, 0], [q(0), q(1)]], {strokeColor: couleur, strokeWidth: 2}); board.create('segment', [[q(0), q(1)], [q(2), q(3)]], {strokeColor: couleur, strokeWidth: 2}); board.create('point', [q(0), q(1)], {name: '', size: 3, color: couleur, fixed: true}); board.create('point', [q(2), q(3)], {name: '', size: 4, color: couleur, fixed: true}); } var ta = board.create('curve', [[0], [0]], {strokeColor: '#1565c0', strokeWidth: 0.6, strokeOpacity: 0.5}); var tb = board.create('curve', [[0], [0]], {strokeColor: '#d32f2f', strokeWidth: 0.6, strokeOpacity: 0.5}); ta.updateDataArray = function () { this.dataX = traceA[0]; this.dataY = traceA[1]; }; tb.updateDataArray = function () { this.dataX = traceB[0]; this.dataY = traceB[1]; }; bras(function () { return A; }, '#1565c0'); bras(function () { return B; }, '#d32f2f'); board.create('point', [0, 0], {name: '', size: 2, color: '#000', fixed: true}); board.create('segment', [[-2.1, -4.2], [2.1, -4.2]], {strokeColor: '#555', strokeWidth: 1}); board.create('segment', [[-2.1, -4.2], [-2.1, -2.55]], {strokeColor: '#555', strokeWidth: 1}); var courbe = board.create('curve', [[0], [0]], {strokeColor: '#6a1b9a', strokeWidth: 1.5}); courbe.updateDataArray = function () { this.dataX = histT; this.dataY = histE; }; var opt = {fontSize: 11, useKatex: false, useMathJax: false, parse: false}; board.create('text', [-2.05, -2.45, 'distance entre les masses du bas (0 à 4 m)'], opt); board.create('text', [0.55, -4.45, 'temps (0 à 30 s)'], opt); board.create('text', [-2.25, 2.1, function () { return 't = ' + t.toFixed(1).replace('.', ',') + ' s'; }], opt); board.create('button', [0.45, 2.1, 'Recommencer', function () { depart(); actif = true; }], {fontSize: 11}); // L'expérience ne démarre que lorsque la figure apparaît à l'écran. var actif = false; if ('IntersectionObserver' in window) { new IntersectionObserver(function (entrees) { if (entrees[0].isIntersecting && !actif) { depart(); actif = true; } }, {threshold: 0.5}).observe(board.containerObj); } else { actif = true; } setInterval(function () { if (!actif || t >= 30) { return; } for (var k = 0; k < 15; k++) { A = rk4(A, 0.002); B = rk4(B, 0.002); t += 0.002; } var pa = pos(A), pb = pos(B), e = Math.sqrt(Math.pow(pa[2] - pb[2], 2) + Math.pow(pa[3] - pb[3], 2)); traceA[0].push(pa[2]); traceA[1].push(pa[3]); traceB[0].push(pb[2]); traceB[1].push(pb[3]); if (traceA[0].length > 120) { traceA[0].shift(); traceA[1].shift(); traceB[0].shift(); traceB[1].shift(); } histT.push(-2.1 + 4.2*t/30); histE.push(-4.2 + 1.6*e/4); board.update(); }, 30); Deux pendules doubles lâchés à $0{,}0001$ radian près. Patience : ils restent superposés plusieurs secondes avant de se séparer. Le bouton relance l'expérience.
Quand le calcul amplifie l'incertitude

Même sans chaos, certaines formules amplifient fortement les erreurs de mesure, et le programme de physique-chimie sur les incertitudes permet de le voir.

  • Une différence de deux mesures proches. On pèse un récipient vide, $250{,}0$ g, puis plein, $250{,}4$ g, avec une balance précise à $0{,}1$ g. La masse du contenu, $0{,}4$ g, est connue à $0{,}2$ g près dans le pire des cas : l'incertitude relative passe de $0{,}04\,\%$ sur chaque pesée à $50\,\%$ sur le résultat.
  • Deux droites presque parallèles. Le système $x + y = 2$ et $x + 1{,}0001\,y = 2{,}0001$ a pour solution $(1\,;1)$. Si le second membre devient $2{,}0002$, une modification d'un dix-millième, la solution devient $(0\,;2)$. Déterminer la position d'un point comme intersection de deux visées presque alignées est donc très imprécis.
  • Une croissance exponentielle. Pour $N(t) = N_0\,\mathrm{e}^{kt}$, une erreur relative sur $k$ est multipliée par $kt$ dans le résultat : plus on prévoit loin, plus l'erreur grandit.
En informatique : les calculs de la machine

Un processeur ne calcule pas avec des nombres réels, mais avec des nombres flottants, codés selon la norme IEEE 754 : sur $64$ bits, un signe, un exposant et $52$ bits pour les chiffres, soit environ $16$ chiffres significatifs. Chaque opération est arrondie au flottant le plus proche, et les nombres qui n'ont pas d'écriture finie en base $2$, comme $0{,}1$, ne sont jamais représentés exactement.

Combinées au chaos, ces minuscules erreurs d'arrondi produisent des résultats faux. Les expressions $4u(1-u)$ et $4u - 4u^2$ sont mathématiquement égales. Pourtant, en calculant la suite logistique pour $r = 4$ et $u_0 = 0{,}3$ avec l'une puis l'autre, l'ordinateur obtient les mêmes valeurs jusqu'au rang $30$ environ, puis des valeurs différentes : $0{,}992$ et $0{,}9998$ au rang $50$, $0{,}093$ et $0{,}207$ au rang $55$. Les deux résultats sont aussi faux l'un que l'autre : au-delà d'une cinquantaine d'étapes, l'erreur d'arrondi initiale, de l'ordre de $10^{-16}$, a été doublée cinquante fois.

Comprendre la base 2

Nous écrivons les nombres en base $10$ : $345 = 3\times10^2 + 4\times10 + 5$. Un ordinateur les écrit en base $2$, avec seulement les chiffres $0$ et $1$, et des puissances de $2$ : $13 = 8 + 4 + 1 = 1\times2^3 + 1\times2^2 + 0\times2 + 1$, ce qui s'écrit $1101$ en base $2$. Après la virgule, les chiffres valent $\dfrac{1}{2}$, $\dfrac{1}{4}$, $\dfrac{1}{8}$… ainsi $0{,}5$ s'écrit $0{,}1$ et $0{,}75 = \dfrac{1}{2} + \dfrac{1}{4}$ s'écrit $0{,}11$ en base $2$.

Pour écrire $0{,}1$ en base $2$, on multiplie par $2$ et l'on garde la partie entière, qui donne le chiffre suivant :

calculchiffre
$0{,}1\times2 = 0{,}2$$0$
$0{,}2\times2 = 0{,}4$$0$
$0{,}4\times2 = 0{,}8$$0$
$0{,}8\times2 = 1{,}6$$1$
$0{,}6\times2 = 1{,}2$$1$
$0{,}2\times2 = 0{,}4$$0$ (on retrouve $0{,}2$ : tout recommence)

Ainsi $0{,}1 = 0{,}000110011001100110011\ldots$ en base $2$, le motif $0011$ se répétant sans fin. C'est la même situation que $\dfrac{1}{3} = 0{,}3333\ldots$ en base $10$ : une fraction n'a d'écriture finie en base $2$ que si son dénominateur est une puissance de $2$, et $10 = 2\times5$ ne l'est pas. Une machine qui garde un nombre limité de chiffres doit donc couper l'écriture de $0{,}1$, et commet une petite erreur.

1991 : le missile Patriot de Dhahran

Pendant la guerre du Golfe, les batteries américaines de missiles Patriot protégeaient l'Arabie saoudite contre les missiles irakiens Scud. Pour intercepter un Scud, le système calcule où il se trouvera, à partir de sa vitesse et du temps écoulé. L'horloge du système comptait le temps en dixièmes de seconde, sous la forme d'un nombre entier, puis le multipliait par $0{,}1$ pour obtenir des secondes. Mais le nombre $0{,}1$ était rangé dans un registre qui ne gardait que $23$ chiffres binaires après la virgule :

$$0{,}000\,1100\,1100\,1100\,1100\,1100_{\,2}$$

c'est-à-dire

$$\frac{838\,860}{2^{23}} \approx 0{,}099\,999\,904\,6.$$

À chaque dixième de seconde, l'horloge perdait donc environ $0{,}000\,000\,095$ seconde. C'est infime, mais l'erreur s'accumule : en cent heures de fonctionnement continu, il s'écoule $100\times3\,600\times10 = 3\,600\,000$ dixièmes de seconde, et l'horloge a dérivé de

$$3\,600\,000 \times 0{,}000\,000\,095 \approx 0{,}34 \text{ s}.$$

Un Scud vole à environ $1\,676$ m/s : en $0{,}34$ s, il parcourt plus de $570$ mètres. Le radar cherchait donc le missile au mauvais endroit. Le 25 février 1991, à Dhahran, la batterie fonctionnait sans interruption depuis une centaine d'heures ; elle ne détecta pas le Scud, qui frappa une caserne et tua $28$ soldats américains. Le défaut était connu : on avait constaté la dérive et conseillé de redémarrer régulièrement le système, et une version corrigée du logiciel arriva le lendemain.

n = int(0.1 * 2**23) # 0,1 tronqué à 23 chiffres binaires valeur = n / 2**23 erreur = 0.1 - valeur print(n, valeur, erreur) dixiemes = 100 * 3600 * 10 # dixièmes de seconde en 100 heures derive = dixiemes * erreur print("dérive :", derive, "s, soit", derive * 1676, "m pour un Scud")
1982-1983 : l'indice de la Bourse de Vancouver

En janvier 1982, la Bourse de Vancouver, au Canada, crée un nouvel indice boursier, fixé à $1\,000$ points. À chaque transaction, l'indice est recalculé à partir de sa valeur précédente, environ $3\,000$ fois par jour. Le programme garde trois décimales, mais au lieu d'arrondir le résultat, il le tronque : il supprime simplement les chiffres en trop. Ainsi $1\,000{,}123\,9$ devient $1\,000{,}123$ et non $1\,000{,}124$.

La différence est essentielle. Un arrondi se trompe tantôt vers le haut, tantôt vers le bas, et les erreurs se compensent en moyenne. Une troncature se trompe toujours dans le même sens, vers le bas, et perd en moyenne la moitié d'un millième, soit $0{,}000\,5$ point, à chaque calcul. Multipliée par $3\,000$ calculs par jour, la perte atteint environ $1{,}5$ point par jour, une vingtaine de points par mois. Pendant vingt-deux mois, l'indice baisse alors que le marché monte. En novembre 1983, on découvre l'erreur et l'on recalcule l'indice : un vendredi soir il valait $524{,}811$ ; le lundi suivant, il vaut $1\,098{,}892$.

var graine = 2024; function hasard() { graine = (graine * 16807) % 2147483647; return graine / 2147483647; } var exact = 1000, tronque = 1000, X = [0], E = [1000], T = [1000], j, k, d; for (j = 1; j <= 462; j++) { for (k = 0; k < 3000; k++) { d = (2*hasard() - 1) * 0.00012; exact = exact * (1 + d); tronque = Math.floor(tronque * (1 + d) * 1000) / 1000; } X.push(j); E.push(exact); T.push(tronque); } board.create('curve', [X, E], {strokeColor: '#1565c0', strokeWidth: 1.5}); board.create('curve', [X, T], {strokeColor: '#d32f2f', strokeWidth: 1.5}); Une simulation : le même indice, recalculé $3\,000$ fois par jour pendant $462$ jours de bourse, en gardant tous les chiffres (bleu) ou en tronquant à trois décimales (rouge).
1996 : le premier vol d'Ariane 5

Un ordinateur ne range pas tous les nombres de la même façon. Un flottant sur $64$ bits peut représenter des nombres immenses, jusqu'à environ $10^{308}$. Un entier signé sur $16$ bits n'a que $2^{16} = 65\,536$ valeurs possibles, de $-32\,768$ à $32\,767$. Convertir un flottant en entier sur $16$ bits n'est donc possible que si le nombre est dans cet intervalle ; sinon, il y a dépassement de capacité.

Le 4 juin 1996, à Kourou, la nouvelle fusée européenne Ariane 5 décolle pour la première fois, avec quatre satellites scientifiques. Son système de guidage, la centrale inertielle, reprend le logiciel d'Ariane 4, qui avait fait ses preuves. Une fonction de ce logiciel, utile seulement avant le décollage, continuait à tourner une quarantaine de secondes après. Elle calculait une grandeur liée à la vitesse horizontale de la fusée, puis la convertissait en entier sur $16$ bits. Sur Ariane 4, cette valeur restait toujours petite. Mais Ariane 5, plus puissante, prend de la vitesse horizontale beaucoup plus vite : la valeur dépasse $32\,767$, la conversion échoue.

Le logiciel avait été conçu pour arrêter la centrale en cas d'erreur. La centrale de secours, qui exécutait exactement le même programme, venait de s'arrêter pour la même raison. La centrale principale envoya alors à l'ordinateur de bord un message d'erreur, que celui-ci interpréta comme des données de vol : il braqua les tuyères à fond. La fusée pivota, se brisa sous l'effet des forces aérodynamiques et s'autodétruisit $37$ secondes après le décollage. Les pertes dépassèrent $370$ millions de dollars. Le rapport d'enquête retient deux leçons : réutiliser un logiciel sans vérifier qu'il est adapté au nouveau contexte, et doubler un équipement ne protège de rien si les deux exemplaires ont le même défaut.

def vers_entier_16_bits(x): n = int(x) if n < -32768 or n > 32767: return "dépassement de capacité" return n print(vers_entier_16_bits(20000.7)) print(vers_entier_16_bits(40000.2)) # Dans beaucoup de langages, un entier sur 16 bits qui déborde « fait le tour » : print(((32767 + 1 + 32768) % 65536) - 32768)
En économie et en biologie

Le diagramme en toile d'araignée porte aussi un nom en économie : le modèle du cobweb (« toile d'araignée » en anglais), étudié dans les années 1930 par Nicholas Kaldor. Un agriculteur décide de ce qu'il va produire l'an prochain en fonction du prix de cette année ; mais le prix de l'an prochain dépendra de la quantité produite par tous. Si le prix est haut, tous produisent beaucoup, l'offre abonde et le prix chute ; alors ils produisent peu, et le prix remonte. Le prix suit une suite récurrente : selon la réactivité de l'offre et de la demande, il converge vers l'équilibre en oscillant, ou oscille de plus en plus fort. On a observé de tels cycles pour le prix du porc ou de certaines récoltes.

Dans la figure, la droite bleue est la demande (plus le prix est bas, plus on achète) et la droite verte est l'offre (plus le prix de l'an passé était haut, plus on produit). Partant d'un prix bas, on suit le chemin rouge : la quantité produite se lit sur l'offre, le prix qui en résulte sur la demande, et ainsi d'année en année. Le curseur règle la réactivité des producteurs : si elle est faible, le prix converge vers l'équilibre ; si elle est égale à celle de la demande, le prix oscille indéfiniment ; si elle est plus forte, les oscillations s'amplifient.

var d = board.create('slider', [[2.2, 11.4], [6.2, 11.4], [0.5, 0.8, 1.3]], {name: 'réactivité', snapWidth: 0.05, digits: 2}); board.create('functiongraph', [function (q) { return 10 - q; }, 0, 10], {strokeColor: '#1565c0', strokeWidth: 2}); board.create('functiongraph', [function (q) { return q / d.Value(); }, 0, 10], {strokeColor: '#2e7d32', strokeWidth: 2}); var c = board.create('curve', [[0], [0]], {strokeColor: '#d32f2f', strokeWidth: 1.3}); c.updateDataArray = function () { var p = 2, q, k; this.dataX = []; this.dataY = []; for (k = 0; k < 25; k++) { q = d.Value() * p; if (q > 10.5 || p < -0.5) break; this.dataX.push(q); this.dataY.push(p); p = 10 - q; this.dataX.push(q); this.dataY.push(p); } }; var opt = {fontSize: 11, useKatex: false, useMathJax: false, parse: false}; board.create('text', [6.8, 0.6, 'quantité'], opt); board.create('text', [0.2, 10.4, 'prix'], opt); board.update(); Le modèle du cobweb : demande (bleu), offre (vert) et évolution du prix d'année en année (rouge).

Des modèles économiques non linéaires peuvent produire du chaos, et l'instabilité des marchés financiers rappelle la sensibilité aux conditions initiales. Mais il faut rester prudent : en économie, il est très difficile de distinguer un comportement chaotique d'un comportement simplement soumis à de nombreux chocs imprévus, et la question reste discutée.

En biologie, la suite logistique de Verhulst et de May reste un modèle de base de la dynamique des populations. Des populations d'insectes ou de petits rongeurs présentent des cycles réguliers ou des fluctuations irrégulières, et Robert May en tirait une leçon : même un modèle très simple peut produire des fluctuations qui ne sont dues à aucune cause extérieure.

Dans la figure, chaque barre représente la population d'une année, en proportion du maximum que le milieu peut nourrir. Le paramètre $r$ mesure la fécondité de l'espèce. Pour $r = 2{,}8$, la population se stabilise ; vers $r = 3{,}2$, elle alterne années d'abondance et années de disette ; au-delà de $3{,}6$, elle varie de façon désordonnée, sans qu'aucun événement extérieur (climat, maladie, prédateur) n'en soit la cause.

var r = board.create('slider', [[2, 1.14], [18, 1.14], [2.5, 2.8, 4]], {name: 'r', snapWidth: 0.05, digits: 2}); var c = board.create('curve', [[0], [0]], {strokeColor: '#2e7d32', strokeWidth: 5, lineCap: 'butt'}); c.updateDataArray = function () { var u = 0.2, k; this.dataX = []; this.dataY = []; for (k = 0; k <= 30; k++) { this.dataX.push(k, k, NaN); this.dataY.push(0, u, NaN); u = r.Value()*u*(1-u); } }; board.update(); Une population sur trente années selon le modèle de Verhulst, pour différentes valeurs de la fécondité $r$.
Programmer et observer

Le premier programme compare deux suites dont les premiers termes diffèrent d'un dix-millième ; le second calcule la même suite avec deux formules égales. On peut changer les valeurs et les exécuter.

def logistique(r, u, n): termes = [u] for k in range(n): u = r * u * (1 - u) termes.append(u) return termes a = logistique(3.9, 0.2, 30) b = logistique(3.9, 0.2001, 30) for n in range(0, 31, 5): print(n, round(a[n], 4), round(b[n], 4), round(abs(a[n] - b[n]), 4)) u = 0.3 v = 0.3 for n in range(1, 61): u = 4 * u * (1 - u) v = 4 * v - 4 * v * v if n % 10 == 0: print(n, u, v) Ce que l'on peut approfondir en NSI
  • Ne jamais tester l'égalité de deux flottants : on teste plutôt abs(a - b) < epsilon.
  • Choisir la bonne formule : $1 - \cos x = 2\sin^2\dfrac{x}{2}$ évite l'élimination catastrophique.
  • Calcul exact : les fractions (module fractions) ou les nombres décimaux à grande précision (module decimal) évitent les arrondis, au prix de calculs plus lents et de nombres de plus en plus longs.
Des directions pour construire sa question

Ce texte n'est pas un Grand Oral. Il rassemble des connaissances dans lesquelles chacun peut choisir une direction, la creuser et formuler sa propre question. Quelques directions possibles :

Pour l'échange avec le jury : les notions du cours à maîtriser

Le jury peut interroger sur les chapitres de spécialité mobilisés. Avec ce thème, il est utile de connaître parfaitement : les suites définies par récurrence, leur représentation graphique, le raisonnement par récurrence ; la monotonie, les suites bornées, la convergence et le théorème du point fixe ; les fonctions du second degré ; la continuité ; les suites géométriques et la fonction exponentielle ; et en physique, la propagation des incertitudes.

Pour réviser ces chapitres, l'application Maths FlashBac reprend tout le cours de spécialité en cartes.

Pour aller plus loin