CodeGym /Cours /JAVA 25 SELF /Problèmes de précision et valeurs spéciales

Problèmes de précision et valeurs spéciales

JAVA 25 SELF
Niveau 6 , Leçon 3
Disponible

1. Introduction

Il peut sembler que si l’ordinateur est « intelligent », alors 0.1 + 0.2 devrait tout simplement donner 0.3. Mais ce n’est pas tout à fait le cas. Voyons cela avec un exemple simple.


double x = 0.1;
double y = 0.2;
double sum = x + y;
System.out.println(sum); // Que va afficher le programme ?
Addition de nombres à virgule flottante : on s’attend à 0,3, mais qu’en est-il en réalité ?

Et maintenant, essayez de comparer à 0.3 :

System.out.println(sum == 0.3); // Et ici, sera-ce true ou false ?

Si vous voyez false, ne soyez pas surpris !

La raison se cache dans la représentation des nombres en mémoire

Les ordinateurs travaillent en base binaire. Or, loin de toutes les fractions décimales peuvent être représentées comme des fractions binaires finies, tout comme 1/3 ne peut pas être écrit exactement en décimal (0.333...). Par exemple, 0.1 en binaire est une fraction infinie, et il faut l’« arrondir » pour la stocker.

En termes simples, le type double fait parfois semblant de stocker votre nombre exactement, mais en réalité il ne conserve qu’une valeur approchée très proche.

2. Quelles « bizarreries » apparaissent lors de l’arithmétique avec double ?

Voyons des exemples concrets.

Exemple 1. La « magie » classique 0.1 + 0.2

double a = 0.1;
double b = 0.2;
double sum = a + b;
System.out.println(sum);            // 0.30000000000000004
System.out.println(sum == 0.3);     // false

L’ordinateur n’affiche pas 0.3, mais 0.30000000000000004. La différence est minime, mais si vous faites, par exemple, de la finance — c’est déjà critique.

Exemple 2. Addition itérative

double result = 0;
for (int i = 0; i < 10; i++)
{
    result += 0.1;
}
System.out.println(result); // 0.9999999999999999

Vous vouliez 1.0 — vous avez obtenu un peu moins. Là encore, la raison est l’arrondi interne de double.

Pourquoi est-ce important dans des tâches réelles

Beaucoup pensent : « Quelle importance, une petite erreur, et alors ! » Examinons un exemple du monde des paiements.

Supposons que votre banque en ligne additionne 100 transactions de 0.1 €. Si votre programme « perd » un cent‑millième d’euro à chaque itération, à l’échelle d’une banque vous allez déjà « perdre » de l’argent réel. Là, le comptable viendra immédiatement vous voir et demandera : « Où est passé notre argent ?! »

3. Comment comparer correctement les nombres à virgule flottante

Puisque le type double ne peut souvent pas stocker exactement la valeur attendue, une comparaison directe avec == peut vous piéger. À la place, on compare le module de la différence à un très petit nombre (epsilon).

Exemple de comparaison avec une tolérance

double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.000001;

if (Math.abs(a - b) < epsilon)
{
    System.out.println("Presque égal !"); // C’est plus sûr de comparer ainsi
}

Ici, nous disons : « Si la différence entre les nombres est inférieure à un millionième, nous considérons que les nombres sont égaux. »
Remarque : la fonction Math.abs(value) retourne la valeur absolue (module) du nombre passé.

4. Valeurs spéciales de double : Infinity, NaN, -Infinity

Le type double ne stocke pas seulement des nombres, mais aussi des valeurs particulières. Elles apparaissent dans des situations qu’un mathématicien interdit strictement à un étudiant.

Infini (Infinity)

Que se passe‑t‑il si l’on divise 1 par 0 ?

double result = 1.0 / 0.0;
System.out.println(result); // Infinity

En Java (et dans beaucoup d’autres langages), la division par 0 pour un double ne lève pas d’exception ! À la place, le résultat devient une valeur spéciale « infini positif ».

Moins l’infini (-Infinity)

Si vous divisez un nombre négatif par 0, vous obtenez l’infini négatif :

double result = -1.0 / 0.0;
System.out.println(result); // -Infinity

« Pas un nombre » (NaN — Not a Number)

Si vous faites quelque chose de vraiment étrange, par exemple tenter de calculer la racine carrée d’un nombre négatif :

double result = Math.sqrt(-1);
System.out.println(result); // NaN

Ou le résultat de la division 0.0 / 0.0 :

double result = 0.0 / 0.0;
System.out.println(result); // NaN

NaN correspond à « tout ce qui ne serait pas un nombre dans la vraie vie ».

Vérification des valeurs spéciales

Java propose des fonctions pour vérifier ces valeurs :

System.out.println(Double.isInfinite(result));    // true, si infini
System.out.println(Double.isNaN(result));         // true, si NaN

Tableau : comment double réagit aux opérations inhabituelles

Opération Résultat Ce qui est stocké dans double
1.0 / 0.0
Infinity +∞
-1.0 / 0.0
-Infinity -∞
0.0 / 0.0
NaN Pas un nombre
Math.sqrt(-1)
NaN Pas un nombre

5. Erreurs typiques lors du travail avec les nombres à virgule flottante

Erreur n° 1 : comparer des nombres décimaux avec ==
Le piège le plus courant : essayer de vérifier l’égalité de deux nombres à virgule flottante calculés via une comparaison directe. À cause de l’accumulation des erreurs d’arrondi, vous obtiendrez presque toujours un résultat inattendu. Utilisez toujours une comparaison avec tolérance (epsilon).

Erreur n° 2 : NaN et Infinity inattendus dans les calculs
Si vous ne contrôlez pas la division par zéro ou les racines de nombres négatifs, votre programme peut produire NaN ou Infinity et « contaminer » tous les calculs suivants. N’oubliez pas de vérifier les valeurs suspectes à l’aide de Double.isNaN() et Double.isInfinite() — cela vous aidera à éviter de mauvaises surprises.

Erreur n° 3 : utiliser NaN comme « marqueur »
Certains débutants utilisent NaN comme valeur « spéciale » pour signaler, par exemple, « si non trouvé — renvoyer NaN ». Mais souvenez‑vous : NaN est piégeux, et la comparaison avec == ne fonctionnera pas ! Vérifiez uniquement via des méthodes dédiées.

Erreur n° 4 : attendre une exception lors d’une division par 0.0
Contrairement à la division entière, la division par 0.0 pour un double ne provoque pas d’erreur, mais retourne Infinity ou NaN. Cela peut mener à des bugs silencieux et difficiles à détecter — il y a un résultat, mais ce n’est pas celui que vous attendiez.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION