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 telle 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 considérer 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).
/* 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.
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 | */