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

User

Corriger les erreurs dans les résultats des opérations en virgule flottante

Noter ce billet
par , 29/01/2021 à 12h09 (1731 Affichages)
Objectif : corriger les erreurs dans les résultats des opérations portant sur des nombres à virgule flottante, floating-point error en anglais.

En VBA le type Double par exemple, contient des nombres à virgule flottante double précision IEEE 64 bits (8 octets) compris entre-1.79769313486231570 E+308 et -4.94065645841246544 E-324 pour les valeurs négatives et de 4.94065645841246544 E-324 à 1.79769313486231570 E+308 pour les valeurs positives.

Les nombres à double précision stockent une approximation d’un nombre réel. Ceci explique pourquoi il peut y avoir de légères imprécisions quand on effectue des opérations sur ces nombres.

Par exemple, si vous souhaitez représenter Pi ou 1/3 sous une forme décimale, il est évident que vous n'obtiendrez jamais une valeur exacte.

Au cours du développement, si vous n'avez pas la possibilité d'utiliser un type décimal ou monétaire à la place, vous pouvez avoir à corriger des erreurs dans les résultats des opérations portant sur des nombres à virgule flottante.


I. Correction des erreurs sur les résultats d'opérations

Prenez par exemple une simple soustraction entre 2 nombres :

12.1 - 12 donne 0,0999999999999996 au lieu de 0.1

Dans ce cas, il faut utiliser la fonction Round(nombre, nombre_décimales), pour arrondir le résultat avec une certaine précision et ainsi corriger l'erreur :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
? Round(12.1 - 12, 5)

va bien donner 0.1

choisir pour l'arrondi un nombre de décimales suffisamment grand pour ne pas arrondir de trop le nombre.

Dans les formulaires Access, ces erreurs peuvent aussi être corrigées sur les sommes de valeurs affichées dans des zones de texte :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
= Round(somme([champ_valeur]);5)

Ou dans une requête :

Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
select Round(Sum([colonne_valeur]),5) as total
from table_valeurs;

Ou encore dans une cellule d'une feuille Excel, C1 étant la cellule contenant le résultat à corriger :



II. Correction des erreurs de comparaison entre valeurs numériques

Ces problèmes peuvent aussi se rencontrer quand on souhaite effectuer une comparaison entre valeurs dans le code :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
    if somme_valeurs >= 2000# then ' teste si la somme est supérieure ou égale à un certain seuil de 2000
	' traitement si condition respectée
    end if


Imaginez que la valeur de la variable somme_valeurs soit le résultat d'une somme de nombres à virgule flottante, il se peut que le total donne par exemple 1999.9999999999999996, au lieu de 2000, et dans ce cas la condition ne serait pas respectée alors qu'elle devrait l'être.

Pour corriger l'erreur dans la somme et faire en sorte que la condition soit respectée, vous pouvez à nouveau utiliser la fonction Round :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
    if Round(somme_valeurs,5) >= 2000# then ' teste si la somme est supérieure ou égale à un certain seuil de 2000
	' traitement si condition respectée
    end if

Si vous souhaitez maintenant simplement vérifier si la somme est égal à 2000 :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
    if somme_valeurs = 2000# then ' teste si la somme est égale à un certain seuil de 2000
	' traitement si condition respectée
    end if

Vous pouvez également contrôler si l'écart en valeur absolue entre les 2 nombres ne dépasse pas une certaine marge d'erreur :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
    if Abs(somme_valeurs - 2000#) <= 0.000001 then ' teste si l'écart en valeur absolue entre les 2 nombres ne dépasse pas une marge d'erreur de 0.000001
	' traitement si condition respectée
    end if


III. Correction des erreurs de comparaison entre dates

Ces erreurs peuvent aussi se produire quand on effectue des opérations sur des dates qui sont en fait stockées sous forme de nombres à virgule flottante. La partie entière représente la date et la partie décimale l'heure.

Prenons deux variables de type Date, dt1 et dt2, initialisées au 29/01/2021 14:00 soit en VBA au #1/29/2021 2:00:00 PM# :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
    Dim dt1 as date, dt2 as date
 
     ' initialisation des variables
    dt1 = #1/29/2021 2:00:00 PM#
    dt2 = #1/29/2021 2:00:00 PM#

Ajoutons deux fois 15 minutes à la variable dt1, et directement 30 minutes à la variable dt2 :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
    dt1 = DateAdd("n", 15, dt1)  ' ajoutons 15 minutes à la date de départ du 29/01/2021 à 14:00
    dt1 = DateAdd("n", 15, dt1) ' ajoutons encore 15 minutes à la date obtenue
 
    dt2 = DateAdd("n", 30, dt2)  ' ajoutons directement 30 minutes à la date de départ du 29/01/2021 à 14:00

Comparons maintenant les variables qui devraient logiquement contenir toutes deux la valeur #1/29/2021 2:30:00 PM# :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
    If dt1 = dt2 Then ' comparons les 2 dates obtenues
        Debug.Print "les dates sont égales !"
    Else
        Debug.Print "les dates ne sont pas égales !"
    End If

L'exécution du code complet affiche pourtant "Les dates ne sont pas égales !"

On est a nouveau en présence d'erreurs de précision dans les résultats d'opérations portant sur des nombres à virgule flottante, les valeurs numériques des deux dates obtenues étant légèrement différentes.

La solution passe une nouvelle fois par l'utilisation de la fonction Round pour comparer les dates :

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
    If Round(dt1,5) = Round(dt2,5) Then ' comparons les 2 dates obtenues
        Debug.Print "les dates sont égales !"
    Else
        Debug.Print "les dates ne sont pas égales !"
    End If

Après cette modification, l'exécution du code donne bien "Les dates sont égales !"

Vous pouvez bien sûr également utiliser la fonction format pour les comparaisons avec if format(dt1,"dd/mm/yyyy hh:nn:ss") = format(dt2,"dd/mm/yyyy hh:nn:ss") then.

Voilà, j'espère que ça en aidera certains, car j'ai moi-même été pas mal dérouté au début pas ces problèmes avec les nombres à virgule flottante : on obtient un résultat inattendu alors qu'on a tout bien fait

Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog Viadeo Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog Twitter Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog Google Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog Facebook Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog Digg Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog Delicious Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog MySpace Envoyer le billet « Corriger les erreurs dans les résultats des opérations en virgule flottante » dans le blog Yahoo

Catégories
Programmation , Access , VBA , Excel

Commentaires