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 5 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

Aussi, chaque fois que l’on veut comparer deux nombres flottants, il faut spécifier avec quelle précision on veut les comparer. Comme on manipule certaines fois des nombres très grands et d’autres fois des nombres très petits, ce qui compte c’est la précision relative: le nombre de chiffres significatifs en communs.

Par exemple, 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:

\[ |x - y| < \varepsilon|x| \qquad \text{et} \qquad |x - y| < \varepsilon |y|\]

Moralement: la différence entre \(x\) et \(y\) est négligeable devant \(x\) et devant \(y\).

Implantation

Implantez les deux fonctions suivantes dont on vous donne la documentation :

  • abs mais qui prend cette fois en paramètre un double et retourne un double

  • 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.