TP : implanter la fonction exponentielle (3/5)#
Partie 3 : comparaison de nombres flottants et précision relative#
Sur les nombres flottants (float
ou double
) l’opérateur ==
n’est
pas toujours très fiable à cause des erreurs d’arrondis :
1.0 + 1e20 - 1e20 == 1e20 - 1e20 + 1.0
Exécutez les cinq cellules suivantes. Que constatez-vous ?
BEGIN SOLUTION
a
et b
ont bien des valeurs différentes mais s’affichent de la
même manière.
END SOLUTION
double a,b;
a = 16;
b = 15.99999999999;
a
b
(a == b)
Définition : précision relative#
Chaque fois que l’on veut comparer deux nombres flottants, il faut spécifier avec quelle précision on veut les comparer.
Le plus simple est de fixer une précision absolue \(\eta\), c’est-à-dire la différence de valeur seuil en dessous de laquelle on considère que deux nombres sont égaux : \(x \approx y\) si \(|x - y| < \eta\).
Cependant, cette valeur de précision absolue peut être difficile à fixer, surtout quand les valeurs sont très variables en ordre de grandeur. Par exemple, si l’on considère des hauteurs de pics montagneux, on pourrait largement se satisfaire d’être précis à la dizaine de mètres (\(\eta = 10^1\)m) près. En revanche si l’on compare des tailles de personnes, on aimerait pouvoir être précis au centimètre (\(\eta = 10^{-2}\)m). On aurait donc besoin de précisions absolues totalement différentes selon l’ordre de grandeur des valeurs.
En fait c’est le nombre de chiffres significatifs en commun qui est pertinent à mesurer. Formellement, on utilise alors une précision relative. Si on veut comparer \(x\) et \(y\) avec une précision relative de cinq chiffres significatifs, on prendra \(\varepsilon=10^{-5}=0,00001\), et on dira que \(x\) est égal à \(y\) à \(\varepsilon\) près si :
Moralement : la différence entre \(x\) et \(y\) est négligeable devant \(x\) et devant \(y\).
Ce concept est particulièrement pertinent dans notre cas, car l’exponentielle donne des valeurs d’ordre de grandeur qui varie très vite : \(e^1 \simeq 10^0\), \(e^5 \simeq 10^2\), \(e^{10} \simeq 10^5\) …
Implantation#
Implantez les deux fonctions suivantes dont on vous donne la documentation :
abs
mais qui prend cette fois en paramètre undouble
et retourne undouble
egal
qui prend en paramètre les nombres \(x\), \(y\) et \(\varepsilon\).
/** Valeur absolue pour type double
* @param x un nombre de type double
* @return la valeur absolue de x
**/
/// BEGIN SOLUTION
double abs(double x) {
if (x < 0) {
return -x;
} else {
return x;
}
}
/// END SOLUTION
abs(-1.5)
CHECK( abs(-1.5) == 1.5 );
CHECK( abs( 2.2) == 2.2 );
/** Égalité entre deux flottants avec précision relative
* @param x un nombre de type double
* @param y un nombre de type double
* @param epsilon un nombre de type double
* @return true si la valeur absolue de x - y est plus petite que epsilon * |x| et que epsilon * |y|
**/
/// BEGIN SOLUTION
bool egal(double x, double y, double epsilon) {
double v = abs(x-y);
return ((v < epsilon * abs(x)) and (v < epsilon * abs(y)));
}
/// END SOLUTION
egal(15.999999, 16,0.00001)
CHECK( egal(15.999999, 16, 0.00001) == true );
CHECK( egal(15.99, 16, 0.00001) == false );
Trouvez des valeurs de epsilon
telles que les nombres ci-dessous
soient considérés comme égaux par egal
:
egal(15, 16, 0.001)
egal(0.0001, 0.002, 0.00001)
Que se passe-t-il lorsque \(x\) ou \(y\) valent 0 ?
BEGIN SOLUTION
Lorsque \(x\) ou \(y\) valent 0 (même lorsque les deux valent 0), la
fonction egal
retourne toujours false
. On ne peux pas parler de
précision relative à zéro.
END SOLUTION
egal(0.00001, 0, 0.0000001)
Bilan de la partie 3#
Maintenant que la notion de précision relative est bien définie, et que vous avez implanté la comparaison de nombres flottants avec une précision relative fixée, vous pouvez passer à la partie 4.