Chapitre 6 : Estimation d erreurs numériques Puisque les réels ne sont représentés en machine que sous la forme de flottants, ils ne sont connus que de manière approchée. De plus, la somme ou le produit de deux flottants est également approchée. On va voir dans ce chapitre comment les erreurs se propagent, et on étudiera par l exemple les phénomènes d instabilité numérique, en essayant de voir comment limiter les effets néfastes de l approximation. 1 Rappels sur la représentation des nombres réels On rappelle qu un flottant normalisé se représente avec m bits de mantisse sous la forme x = ( 1) s 1, M 1 M m 2 2 E où les M i {, 1} sont les bits de la mantisse, stockés de manière contigue. L exposant et le signe sont également représentés en interne, contrairement au 1 précédant la mantisse. La finitude de m (nombre de bits de la mantisse) implique que les réels ne sont représentés que de manière approchée. Pour x un réel non nul qui n est ni trop grand, ni trop petit en valeur absolue (pour que l exposant associé à son développement en base 2 tienne sur le nombre de bits alloués) en considérant x le flottant le plus proche, on s aperçoit que x x x 2E m 2 E = 2 m Ce nombre est la précision relative donnée par les m bits de mantisse, indépendante du réel représenté. Rappelons que sur 64 bits (ce qui est aujourd hui le nombre de bits usuellement alloués à la représentation d un flottant), m a pour valeur 52. Ainsi la précision relative est de 2 52 2.22 1 16. Dans la suite, on notera ε cette précision relative. 2 Erreurs sur les sommes et produits Lorsque l on effectue une somme ou le produit de deux flottants, le résultat est arrondi au flottant le plus proche. Prenons un exemple : si l on fait l addition de 1 et de 2 1 (tous deux représentables exactement sur 64 bits) alors la somme est arrondie au flottant le plus proche, à savoir 1 lui-même. Peut-on majorer l erreur effectuée? C est ce qu on va voir maintenant. 2.1 Erreur sur la somme Proposition 1. Soient x et y deux réels représentés exactement. Alors en notant (x + y) = x + y x y la valeur absolue de la différence entre la «vraie» somme x + y et le résultat calculé sous forme de flottant x + y, on a (x + y) ε( x + y ), avec ε la précision relative. Démonstration. Admise. Il n est pas dur de se convaincre que la précision relative multipliée par la somme des valeurs absolues majore l erreur : pour effectuer la somme, on décale le plus petit pour réaliser l opération bit par bit : on perd juste les bits les moins significatifs, comme en base 1 : Faisons l addition de 123.4567 et 45.67834 avec 7 chiffres significatifs : Svartz Page 1/6 214/215
1 2 3. 4 5 6 7 4 5. 6 7 8 3 4 1 6 9. 1 3 5 4 Le dernier chiffre sur 7 chiffres significatifs est perdu, on a donc une erreur de 4 1 5. Or ici, avec 7 chiffres significatifs, on a une précision relative de 1 6 (on a seulement 6 chiffres de mantisse), et 169.1354 1 6 majore bien l erreur commise. Cumulation d erreurs. En général, lorsqu on effectue des calculs en série, les opérandes x et y eux-mêmes ne sont connus qu à x et y près. On effectue donc la somme x + y avec x x = x et y y = y. L erreur sur cette somme est majorée par ε( x + y ) ε( x + y + x + y). En négligeant les termes de la forme ε x, on obtient que l erreur entre le résultat obtenu en effectuant x + y par rapport à la «vraie» somme x + y se majore par ε( x + y ) + x + y. Somme sur plusieurs termes. Considérons ici une somme N i=1 u i de termes positifs, qu on cherche à estimer. On peut (mathématiquement) sommer dans n importe quel sens, mais qu en est-il sur des flottants? Supposons que l on somme dans l ordre «naturel» ici. On effectue donc les opérations s k = u k + s k 1 avec s k = k i=1 u i. D après la proposition précédente, on a donc une erreur sur s k qui est majorée par εs k (les termes sont supposés positifs). Ainsi, l erreur cumulée est majorée par n εs k = ε((n 1)u 1 + (n 2)u 2 + + u n ) k=2 (la somme commence à 2 car s 1 = u 1 est sans erreur). On en déduit un principe simple : Lorsqu on effectue une somme de plusieurs termes, il est préférable de sommer d abord les termes les plus petits en valeur absolue. Exemple. Illustrons ceci par un exemple. Vous savez peut-être que exp(x) = + k= xk k!. Cette série converge très vite vers sa limite, donc pour N assez grand, N k= xk k! donne une bonne approximation. On définit ci-dessous deux fonctions exponentielles, faisant la somme jusqu à 1. C est largement suffisant pour dépasser la capacité relative 2 52 si on ne s éloigne pas trop de, on devrait donc calculer le flottant le plus proche de exp(x) de manière exacte. from math import factorial,exp def exp_1(x): s= for i in range(11): s+=x**i/factorial(i) def exp_2(x): s= for i in range(1,-1,-1): s+=x**i/factorial(i) Dans un sens, et dans l autre Comparons les deux fonctions avec la valeur donnée par Python pour e : >>> exp(1)-exp_1(1) -4.44892985626e-16 >>> exp(1)-exp_2(1). Dans la deuxième somme, on a sommé les termes les plus petits en premier : ceux de «la fin» de la série. Cet exemple n est pas forcément le plus pertinent car on reste quand même très proche de la différence relative. Prenons en un autre. Svartz Page 2/6 214/215
6. Là encore, on peut sommer les termes indiffé- Exemple. Vous savez probablement 1 que n remment dans un sens ou dans l autre. def somme(n): s=. for i in range(1,n+1): s+=i*i def somme2(n): s=. for i in range(n,,-1): s+=i*i def somme_exacte(n): return n*(n+1)*(2*n+1)//6 k=1 k2 = n(n+1)(2n+1) Remarquez le s=. dans chacune des deux fonctions, pour forcer Python à travailler avec des flottants (si on avait mis s=, il aurait travaillé avec des entiers, représentés de manière exacte...). Comparons la sortie des deux fonctions de sommation avec la formule exacte (qui donne le résultat exact, puisque c est un entier) : >>> N=1 >>> somme(n)-somme_exacte(n) 3827488. >>> somme2(n)-somme_exacte(n) 92649728. L erreur reste du même ordre de grandeur, mais on est là aussi plus précis lorsqu on somme les plus petits termes d abord (ce qui correspond à somme). 2.2 Erreur sur le produit On ne va pas trop s étendre sur les erreurs apparaissant dans les produits, parce que contrairement aux sommes de plusieurs termes, l erreur apparaissant dans un produit de plusieurs termes ne dépend pas vraiment de l ordre dans lequel le produit est évalué. Proposition 2. Soient x et y deux réels représentés exactement. Alors en notant (xy) = xy xy la valeur absolue de la différence entre le «vrai» produit xy et le résultat calculé sous forme de flottant xy, on a (xy) ε xy, avec ε la précision relative. Démonstration. Admise. Cumulation d erreurs. De même qu avec la somme, si x et y ne sont connus que de manière approchée à x et y près, alors en négligeant les termes de la forme x y ou ε x (qui sont «d ordre 2»), on obtient (xy) y x + x y + ε xy. Erreur sur le produit. Pour des réels (x i ) 1 i n représentés sans erreurs, on montre facilement comme pour la somme que l erreur commise sur le produit est (x 1 x n ) (n 1)ε x 1 x n. Cette estimation ne dépend pas de l ordre choisi pour les facteurs! 3 Phénomènes d instabilité et remèdes On étudie maintenant par l exemple les phénomènes pouvant induire de l instabilité numérique. 3.1 Phénomènes de compensation Le phénomène de compensation se produit lorsque l on soustrait deux nombres très proches : on perd beaucoup de précision sur le résultat. On s en est déja aperçu dans le chapitre sur le pivot de Gauss. Montrons quelques exemples supplémentaires, et essayons de trouver des méthodes pour y remédier. 1. Ce qui se démontre aisément par récurrence, parmi d autres méthodes. Svartz Page 3/6 214/215
Exemple. Commençons par une évaluation simple : >>> 1+1**-15-1 1.11223246251565e-15 Rappelons que l évaluation se fait de gauche à droite. Lors du calcul de 1 + 1 15, on perd beaucoup d information sur le 1 15, qui est très proche de la précision relative ε (on travaille sur 64 bits). On soustrait ensuite 1, très proche de 1 + 1 15, pour obtenir une erreur de plus de 1% sur le résultat théorique 1 15. Exemple : résolution d une équation du second degré. Pour une équation de la forme ax 2 + bx + c = dont le discriminant = b 2 4ac est positif, les deux racines sont données par b± 2a. Si 4ac est petit devant b 2, alors on se retrouve face à un problème de compensation sur l évaluation d une des deux racines. Prenons un exemple en base 1. Considérons l équation x 2 1634x + 2 =, et supposons que l on dispose de 1 chiffres significatifs. Comme b est pair, on calcule plutôt = b2 4 ac. Ainsi : = 667487 donc 816.998776 x 1 = b 2 + et x 1 1633, 998776 x 2 = b 2 et x 2.1224 On n a plus que 5 chiffres significatifs sur x 2! Pour y remédier, on peut remarquer que x 1 x 2 x 2 = 2 x 1 1.223991125 1 3, et ce calcul permet de récupérer nos chiffres significatifs perdus. On peut obtenir la même chose en Python. = 2. Par suite, Deux calculs de x 2.1223991124925681 # obtenu avec la première version.1223991124941416 # obtenu avec la deuxième Vérifions avec scipy : >>> import scipy >>> scipy.roots([1,-1634,2])[1].12239911249414159 On peut retenir un autre principe simple : On essaiera au maximum d éviter les sommations dans lesquelles des termes proches en valeur absolue se compensent. Exemple. Reprenons notre calcul de l exponentielle par la formule exp(x) = + k= xk k!, qu on tronquera encore à k = 1. On veut ce coup-ci calculer exp( 1) (le reste de la série est beaucoup plus petit que ε exp( 1), avec ε la précision relative sur 64 bits). Dans la somme 1 ( 1) k k= k!, les deux termes les plus grands en valeur absolue sont donnés pour k = 9 et k = 1, avec ( 1)1 1! = ( 1)9 9! 2755.731922398589. Comme exp( 1) est de l ordre de 1 5 on a une perte de l ordre de 9 chiffres significatifs si on évalue la somme telle quelle. En effet, en reprenant la fonction exp_2 donnée plus haut : >>> exp_2(-1) 4.5399929291534136e-5 >>> from math import exp ; exp(-1) 4.5399929762484854e-5 Là encore, le remède est simple et utilise le principe évoqué plus haut : on utilise simplement la relation exp( x) = 1 exp(x). >>> 1/exp_2(1) 4.539992976248484e-5 Svartz Page 4/6 214/215
3.2 Problèmes mal posés On étudie ici des problèmes de suites définis par une récurrence, qui bien que mathématiquement corrects, donnent très vite des résultats abérrants à cause des erreurs d approximation. Un calcul d intégrale menant à une suite récurrente. l intégrale suivante : On souhaite calculer une approximation numérique de I n = x n dx 1 + x Parmi plusieurs méthodes possibles, on peut chercher une relation de récurrence entre deux termes successifs de la suite. On obtient facilement : ( ) I = [ln(1 + x)] 1 11 = ln 1 et I n = x n 1 (1 + x 1) dx 1 + x = x n 1 dx 1I n 1 = 1 n 1I n 1 Observons la suite des valeurs données par Python avec ce calcul itératif, en supposant que l on souhaite calculer I 18 de manière approchée : I_=.95311798432493 I_1=.46898219567565 I_2=.311798432493486 I_3=.231535298398455 I_4=.184647991615454 I_5=.153529839845474 I_6=.13137658268211921 I_7=.11485617523635 I_8=.1194398249763648 I_9=.9167128613474629 I_1=.8328713865253717 I_11=.7621952256553738 I_12=.71138176779595 I_13=.5784969245117427 I_14=.13578878977397152 I_15=-.69122123173485 I_16=.75372123173486 I_17=-7.478388781318721 I_18=74.83944336874276 Si le calcul semble réaliste au début, cela devient très vite n importe quoi. En effet, I n est de manière évidente compris entre et 1/1. Bien que la récurrence soit mathématiquement correcte, on peut expliquer ce comportement désastreux. Même en supposant que les 1/n soient calculés exactement, on s aperçoit qu une erreur sur I n 1 est multipliée par 1 lors du calcul de I n. ( 1 n I ) n. Il faut Un remède simple ici consiste à renverser la récurrence, en utilisant plutôt la relation I n 1 = 1 1 donc partir de plus loin, si l on souhaite obtenir I 18. Pour ce faire, il nous faut une approximation de I n qu on peut calculer assez grossièrement : En partant de I 35 1/36, on obtient : I n x n dx 1 = 1 1(n + 1) I_35=.2777777777777778 I_34=.257936579365793 I_33=.26832399626517275 I_32=.27619793437858 I_31=.284882965962146 I_3=.294926241953282 I_29=.339247913856 I_28=.31443517911551653 I_27=.325699339231355 I_26=.33784364472398 I_25=.3583534976664 Svartz Page 5/6 214/215
I_24=.3649164659293397 I_23=.3817527637325 I_22=.39676516688149 I_21=.4148689438766531 I_2=.4347358182819 I_19=.45652964181971895 I_18=.486628252917123 Calculons maintenant avec scipy : >>> from scipy.integrate import quad ; quad(lambda x:x**18/(x+1),,1) (.486628252917125, 5.336429357223825e-17) Remarquez que quad fournit également un terme d erreur. On est donc très précis avec notre renversement de récurrence. Comme ici, l erreur sur I n 1 est à peu près celle sur I n divisée par 1 (sans compter l approximation sur 1/n), on obtient théoriquement une valeur de I 18 à 1 17 près.rès vite quelque chose de très précis. On aurait pu estimer beaucoup plus grossièrement le terme de départ, à condition de partir d un peu plus loin : on obtient le même résultat sur I 18 en partant de l approximation 2 I 5 1 2. Suites définies par une relation de récurrence de la forme u n+1 = f(u n ). Dans la même veine que l étude précédente, on peut se demander comment évoluent les erreurs dans un calcul d une suite (u n ) définie par une récurrence de la forme u n+1 = f(u n ). Donnons une estimation de l erreur relative un+1 u n+1 d un terme en fonction du précédent. Si x et proche de x, alors f( x) f(x) + f (x)( x x). L erreur relative est donc multipliée par f (x). Ce qui nous intéresse est plutôt l erreur relative, qu on calcule comme suit : f(x) f(x) f( x) xf (x) x f(x) f(x) f(x) x La quantité κ(x) = xf (x) f(x) se nomme le conditionnement. Si, lors du calcul de termes de la suite (u n ) n N, on se trouve dans un intervalle sur lequel κ(x) > 1, il faudra faire attention car les erreurs relatives seront dilatées. Considérons par exemple la suite définie par : { u = 2 u n+1 = ln(u n ) pour n. Le conditionnement associé à la fonction x ln(x) en x > est donné par κ(x) = 1 ln(x). On donne ici quelques valeurs approchées de la suite et les conditionnements associés. u = 2 u 1 =.693147185599453 κ(u ) = 1.44269548889634 u 2 =.3665129258166435 κ(u 1 ) = 2.728416772911495 u 3 = 1.3721543231 κ(u 2 ) =.9962922939417376 u 4 =.3714596637856 κ(u 3 ) = 269.282337615291 u 5 = 5.595485183341199 κ(u 4 ) =.17871551212434 u 6 = 1.72196553126855 κ(u 5 ) =.5873356473329 u 7 =.54346329539631 κ(u 6 ) = 1.84596838285 u 8 =.697932673451253 κ(u 7 ) = 1.639934242382 u 9 =.49463528524799216 κ(u 8 ) = 2.216915974739575 u 1 =.73934585469151 κ(u 9 ) = 1.4258654453997 u 11 =.35169845526566 κ(u 1 ) = 2.848436384667697 u 12 = 1.4677852248318 κ(u 11 ) =.9553196199576278 u 13 =.45793139155714 κ(u 12 ) = 21.8773793445418 u 16 =.1192917193512947 κ(u 15 ) = 8.38281154876747 u 24 = 1.971438992348 κ(u 23 ) =.99929537855239 u 25 =.979674584665 κ(u 24 ) = 129.964988749 De temps en temps, u n est très proche de 1, et le conditionnement est grand. Si ici l erreur est encore faible (le produit des conditionnements rencontrés reste bien inférieur à 1 16 ) ; très vite, les valeurs calculées ne seront plus pertinentes. 2. Oui, c est extrèmement grossier! Svartz Page 6/6 214/215