Ce qui semble ne pas avoir été mentionné jusqu'ici, ce sont les concepts d'un algorithme instable et d'un problème mal conditionné . Je vais aborder le premier en premier, car cela semble être un écueil plus fréquent pour les numericists novices.
Considérons le calcul des puissances du nombre d'or (réciproque) φ=0.61803…
; Une solution possible consiste à utiliser la formule de récurrence φ^n=φ^(n-2)-φ^(n-1)
, en commençant par φ^0=1
et φ^1=φ
. Si vous exécutez cette récursivité dans votre environnement informatique favori et comparez les résultats avec des puissances évaluées avec précision, vous constaterez une lente érosion des chiffres significatifs. Voici ce qui se passe par exemple dans Mathematica :
ph = N[1/GoldenRatio];
Nest[Append[#1, #1[[-2]] - #1[[-1]]] & , {1, ph}, 50] - ph^Range[0, 51]
{0., 0., 1.1102230246251565*^-16, -5.551115123125783*^-17, 2.220446049250313*^-16,
-2.3592239273284576*^-16, 4.85722573273506*^-16, -7.147060721024445*^-16,
1.2073675392798577*^-15, -1.916869440954372*^-15, 3.1259717037102064*^-15,
-5.0411064211886014*^-15, 8.16837916750579*^-15, -1.3209051907825398*^-14,
2.1377864756200182*^-14, -3.458669982359108*^-14, 5.596472721011714*^-14,
-9.055131861349097*^-14, 1.465160458236081*^-13, -2.370673237795176*^-13,
3.835834102607072*^-13, -6.206507137114341*^-13, 1.004234127360273*^-12,
-1.6248848342954435*^-12, 2.6291189633497825*^-12, -4.254003796798193*^-12,
6.883122762265558*^-12, -1.1137126558640235*^-11, 1.8020249321541067*^-11,
-2.9157375879969544*^-11, 4.717762520172237*^-11, -7.633500108148015*^-11,
1.23512626283229*^-10, -1.9984762736468268*^-10, 3.233602536479646*^-10,
-5.232078810126407*^-10, 8.465681346606119*^-10, -1.3697760156732426*^-9,
2.216344150333856*^-9, -3.5861201660070964*^-9, 5.802464316340953*^-9,
-9.388584482348049*^-9, 1.5191048798689004*^-8, -2.457963328103705*^-8,
3.9770682079726053*^-8, -6.43503153607631*^-8, 1.0412099744048916*^-7,
-1.6847131280125227*^-7, 2.725923102417414*^-7, -4.4106362304299367*^-7,
7.136559332847351*^-7, -1.1547195563277288*^-6}
Le résultat supposé pour φ^41
a le mauvais signe et, même avant, les valeurs calculées et réelles pour le φ^39
partage sans chiffres en commun ( 3.484899258054952
* ^ - 9 for the computed version against the true value
7.071019424062048 *^-9
). L'algorithme est donc instable, et il ne faut pas utiliser cette formule de récurrence en arithmétique inexacte. Cela est dû à la nature inhérente de la formule de récursivité: il existe une solution "décroissante" et "croissante" à cette récursion, et essayer de calculer la solution "décroissante" par solution en aval lorsqu'il existe une solution alternative "croissante" pour le deuil numérique. Il faut donc s’assurer que ses algorithmes numériques sont stables.
Passons maintenant au concept de problème mal conditionné : même s’il peut exister un moyen stable de faire quelque chose de manière numérique, il se peut très bien que le problème que vous avez ne puisse pas être résolu par votre algorithme. C'est la faute du problème lui-même et non la méthode de la solution. L'exemple canonique en numérique est la solution d'équations linéaires impliquant la "matrice de Hilbert":
La matrice est l'exemple canonique d'une matrice mal conditionnée : essayer de résoudre un système avec une grande matrice de Hilbert pourrait donner une solution inexacte.
Voici une démonstration de Mathematica : comparez les résultats de l'arithmétique exacte
Table[LinearSolve[HilbertMatrix[n], HilbertMatrix[n].ConstantArray[1, n]], {n, 2, 12}]
{{1, 1}, {1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1,
1}, {1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1,
1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
et arithmétique inexacte
Table[LinearSolve[N[HilbertMatrix[n]], N[HilbertMatrix[n].ConstantArray[1, n]]], {n, 2, 12}]
{{1., 1.}, {1., 1., 1.}, {1., 1., 1., 1.}, {1., 1., 1., 1., 1.},
{1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1.},
{1., 1., 1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1., 1., 1.},
{1., 1., 1., 0.99997, 1.00014, 0.999618, 1.00062, 0.9994, 1.00031,
0.999931}, {1., 1., 0.999995, 1.00006, 0.999658, 1.00122, 0.997327,
1.00367, 0.996932, 1.00143, 0.999717}, {1., 1., 0.999986, 1.00022,
0.998241, 1.00831, 0.975462, 1.0466, 0.94311, 1.04312, 0.981529,
1.00342}}
(Si vous l'avez essayé dans Mathematica , vous remarquerez quelques messages d'erreur indiquant que le mauvais conditionnement apparaît.)
Dans les deux cas, augmenter simplement la précision n'est pas un remède; cela ne fera que retarder l'érosion inévitable des chiffres.
C'est ce à quoi vous pourriez être confronté. Les solutions peuvent être difficiles: pour la première fois, soit vous retournez à la planche à dessin, soit vous parcourez des revues / livres / tout ce que vous voulez pour savoir si quelqu'un d'autre a proposé une meilleure solution que la vôtre; pour le second, vous abandonnez ou reformulez votre problème en quelque chose de plus simple.
Je vous laisse avec une citation de Dianne O'Leary:
La vie peut nous jeter des problèmes mal conditionnés, mais il n'y a pas de bonne raison de se contenter d'un algorithme instable.