IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Concepts avancés du langage C

Concepts avancés du langage C


précédentsommairesuivant

III. Manipulation des flottants

III-A. Les nombres flottants

L'opérateur == est défini pour les nombres réels cependant, étant donné que cet opérateur ne fait qu'une comparaison bit à bit des valeurs comparées, il ne doit être utilisé que pour ce type de comparaison or ce n'est généralement pas ce que l'on souhaite faire. Pour tester l'égalité de deux réels, il faut calculer leur différence et voir si elle est assez petite (et assez petite est à définir par le programmeur !). En effet, les calculs avec les nombres réels ne se font pas toujours avec une précision infinie. Cela signifie qu'un calcul qui devrait donner pour résultat 0.0 par exemple peut ne pas retourner exactement 0.0 à cause des éventuelles pertes en précision qui ont pu avoir lieu lors des calculs intermédiaires et c'est pourquoi, le programmeur doit toujours lui-même définir une certaine tolérance à l'erreur à chaque calcul utilisant les nombres réels.

La source de ce problème, c'est qu'il existe une infinité de nombres réels et l'ordinateur n'est bien entendu pas capable de pouvoir les représenter tous. En d'autres termes, l'ensemble des nombres représentables par l'ordinateur est discret et fini et non continu. La distance entre deux réels consécutifs de cet ensemble n'est cependant pas forcément constante. Il existe une macro définie dans float.h appelée DBL_EPSILON qui représente la plus petite valeur x de type double tel que 1.0 + x != 1.0. En d'autres termes, DBL_EPSILON est le réel tel que le successeur de 1.0 dans l'ensemble des nombres représentables par le système est 1.0 + DBL_EPSILON.

Donc comment choisir epsilon ? Tout dépend de l'ordre de grandeur des valeurs comparées et de la tolérance à l'erreur que l'on veut avoir. Il n'y a donc rien d'absolu (ou "d'universel") que l'on peut affirmer sur ce sujet. Si les nombres comparés sont de l'ordre de l'unité (mais pas trop proches de zéro), on peut choisir un epsilon absolu. Si la distance entre les deux nombres (c'est-à-dire |x - y|) est inférieure à epsilon, alors on doit les considérer comme "égaux". Dans les autres cas, il faut généralement être beaucoup moins tolérant (comparaison de nombres proches de zéro par exemple) ou beaucoup plus tolérant (comparaison de grands nombres). Il faut par exemple considerer un epsilon e tel que x est égal à y (on suppose que |x| < |y|) s'il existe un réel k tel que |k| < e et y = x + k.x. e est appelée erreur relative maximale autorisée. k est l'erreur relative qu'il y a entre x et y. L'avantage de cette méthode, c'est qu'elle choisit automatiquement le epsilon absolu qui va le mieux en fonction des nombres comparés. C'est donc cette méthode qui est utilisée dans la plupart des applications.

Voici une fonction qui permet de comparer deux réels avec deux epsilons spécifiés : le premier absolu et le deuxième relatif. Choisir 0 comme epsilon absolu pour l'ignorer (c'est-à-dire, comparer directement en utilisant le epsilon relatif).

 
Sélectionnez
/* Fonction dbl_cmp : Compare deux reels x et y */
/* Retourne :                                   */
/*    -1 si x < y                               */
/*     0 si x = y                               */
/*     1 si x > y                               */

int dbl_cmp(double x, double y, double eps_a, double eps_r)
{
    double a, b;
    int ret;

    /* On tente tout d'abord une comparaison bit a bit. */

    if (x < y)
    {
        a = x;
        b = y;
        ret = -1;
    }
    else if (x > y)
    {
        a = y;
        b = x;
        ret = 1;
    }
    else
        ret = 0;

    /* Si x != y, on tente alors une comparaison avec tolerance a l'erreur. */

    if (ret != 0)
    {
        /* Si eps_a != 0, l'utiliser. */
        
        if (b - a < eps_a)
        {
            ret = 0;
        }
        
        if (ret != 0)
        {
            /* Si on a encore ret != 0 (i.e. x != y), utiliser eps_r. */

            if ((b - a) / a < eps_r)
                ret = 0;
        }
    }

    return ret;
}

III-B. Les fonctions mathématiques

Les fonctions mathématiques sont principalement déclarées dans math.h. Le type flottant utilisé par ces fonctions est le type double.

 
Sélectionnez
double sin(double x);
double cos(double x);
double tan(double x);
double asin(double x); /* ArcSin(x) */
double acos(double x);
double atan(double x);
double atan2(double y, double x); /* atan(y/x), définie même si x = 0 */
double exp(double x);
double log(double x); /* ln(x) */
double log10(double x);
double sqrt(double x); /* racine carre (x) */
double pow(double x, double y); /* x puissance y */
double sinh(double x); /* sinus hyperbolique (x) */
double cosh(double x);
double tanh(double x);
double floor(double x); /* E(x) (partie entière (x)) */
double ceil(double x); /* E(x) + 1 */
double fabs(double x); /* | x | */
double fmod(double x, double y); /* x - n*y, | n*y | <= | x | < | (n+1)*y | */

précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Melem. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.