« Découvrir Scilab/Calcul numérique » : différence entre les versions

Contenu supprimé Contenu ajouté
→‎Le problème de la précision et de l'exactitude : effet de bors simple et commande nearfloat()
Ligne 1 735 :
Scilab est destiné à faire du calcul. La précision, l'exactitude des résultats est donc une préoccupation primordiale.
 
La première chose est bien évidemment d'utiliser des méthodes, des algorithmes corrects, validés, documentés. Mais la mise en code de ces algorithmes doit également être correcte. Bien évidemment, la méthode choisie doit être retranscrite fidèlement et sans erreur, mais il faut aussi prendre en compte certains « effets de bord » dus à la représentation des nombres.
 
En effet, Scilab calcule par défaut avec des nombre décimaux codés en virgule flottante à double précision selon la norme [[w:fr:IEEE 754|IEEE754]]. Cela permet de représenter des nombres dont la valeur absolue est comprise entre 10<sup>-307</sup> et 10<sup>308</sup> ; si un calcul donne une valeur inférieure, cela retourne la valeur 0 (erreur de soupassement), et s'il donne une valeur supérieure, cela retourne la valeur Inf ou -Inf–Inf (erreur de dépassement). Le nombre de chiffres significatifs est de l'ordre de 16 ; ainsi, si deux nombres diffèrent au 17<sup>e</sup> chiffre significatif, ils seront considérés comme égaux (erreur d'arrondi), leur différence sera nulle, leur rapport sera de 1.
 
Il faut donc s'assurer d'une part que le valeur finale est représentable, mais aussi que les résultats des calculs intermédiaires sont eux aussi représentables. Par exemple le calcul de <code>abs(-10^-200)</code> donne bien le résultat 10<sup>-200</sup>, alors que <code>sqrt((-10^-200)^2)</code> donne 0, puisque le résultat intermédiaire (-10<sup>200</sup>)<sup>2</sup> n'est pas représentable (soupassement). Dans certains cas, un algorithme itératif, cherchant une valeur approchée, peut donner un meilleur résultat qu'un calcul direct utilisant une formule exacte… Par exemple, pour calculer l’hypoténuse d'un triangle rectangle <math>\sqrt{a^2 + b^2}</math> (norme euclidienne), on peut utiliser la méthode de Moler et Morrison (1983)<ref>{{harvsp|Baudin|2010b|p = 44–45}}</ref>, ce que fait d'ailleurs la commande Scilab <code>norm()</code>.
 
Le problème de la précision peut parfois se manifester sur des calculs « banals ». Par exemple, le vecteur <code>[-5.1:0.2:5.1]</code> devrait contenir les 51 éléments {–5,1 ; –4,9 ; … ; 4,9 ; 5,1}. Or, les cinquante additions successives de la quantité 0,2, du fait des erreurs d'arrondis, font que le dernier élément calculé est légèrement supérieur à 5,1 (il vaut environ 5,1 + 9⋅10<sup>-16</sup>) et donc la liste s'arrête à 4,9. Ce genre de problème peut se gérer avec la commande <code>nearfloat()</code> :
Si l'on doit faire des calculs avec des cas « extrêmes » — nombres très proches, ou bien ayant une valeur absolue élevée ou faible —, on s'intéressera à des algorithmes « robustes ». Ceux-ci font fréquemment intervenir une normalisation des données ou une factorisation pertinente. Dans la mesure du possible, si l'on a le choix entre une fonction « fait maison » et une fonction Scilab faisant le même travail, on favorisera la fonction Scilab, qui est censée être optimisée.
<source lang="scilab">
-5.1:0.2:nearfloat("succ", 5.1)
</source>
ou bien, pour la génération de vecteurs, avec la commande <code>linspace()</code>.
 
Si l'on doit faire des calculs avec des cas « extrêmes » — nombres très proches, ou bien ayant une valeur absolue élevée ou faible —, on s'intéressera à des algorithmes « robustes ». Ceux-ci font fréquemment intervenir une normalisation des données ou une factorisation pertinente. Dans la mesure du possible, si l'on a le choix entre une fonction « fait maison » et une fonction Scilab faisant le même travail, on favorisera la fonction Scilab, qui est censée être optimisée.
 
Si des calculs intermédiaires font intervenir des nombres positifs très grands ou très petits, on peut utiliser la fonction logarithme, qui a initialement été inventée pour cela. Par exemple, pour calculer
: <math>1 - \frac{365!}{(365 - 23)! \times 365^{23}} \simeq 0,507</math> avec <math>365! \simeq 10^{778} \gg 10^{308}</math>
on peut utiliser la fonction logarithme de la fonction gamma, <code>gammaln()</code><ref>voir {{lien web
Ligne 1 764 ⟶ 1 770 :
1 - prod( (343/365):(1/365):(364/365) )
</source>
Pour effectuer des tests, Scilab dispose de la constante spéciale <code>%eps</code> qui est égale à la plus petite valeur absolue représentable.
 
Quoi qu'il en soit, la mise en œuvre d'un algorithme doit toujours s'accompagner de tests avec des valeurs pour lesquelles le résultat est connu. Les résultats de référence peuvent être calculés à la main, obtenus avec un logiciel de référence, ou bien les données peuvent être générées en fonction du résultat attendu.