Comparez double en problème de précision VBA
-
04-07-2019 - |
Question
J'ai des difficultés à comparer 2 doubles dans Excel VBA
supposons que j'ai le code suivant
Dim a as double
Dim b as double
a = 0.15
b = 0.01
Après quelques manipulations sur b, b est maintenant égal à 0,6
Cependant, l'imprécision liée au type de données double me donne mal à la tête parce que
if a = b then
//this will never trigger
end if
Savez-vous comment je peux supprimer l’imprécision de fuite sur le type double?
La solution
Vous ne pouvez pas comparer les valeurs à virgule flottante pour l'égalité. Voir cet article sur " Comparaison des flottants nombres " pour une discussion sur la façon de gérer l'erreur intrinsèque.
Il n’est pas aussi simple que de comparer à une marge d’erreur constante à moins de savoir avec certitude quelle est la plage absolue des flotteurs.
Autres conseils
si vous allez faire cela ....
Dim a as double
Dim b as double
a = 0.15
b = 0.01
vous devez ajouter la fonction round dans votre déclaration IF comme ceci ...
If Round(a,2) = Round(b,2) Then
//code inside block will now trigger.
End If
Voir aussi ici pour une référence Microsoft supplémentaire .
Il n’est jamais sage de comparer les doubles en égalité.
Certaines valeurs décimales correspondent à plusieurs représentations en virgule flottante. Donc, un 0.6 n'est pas toujours égal à l'autre 0.6.
Si nous soustrayons l'un de l'autre, nous obtenons probablement quelque chose comme 0.00000000051.
Nous pouvons maintenant définir l'égalité comme ayant une différence inférieure à une certaine marge d'erreur.
Voici une fonction simple que j'ai écrite:
Function dblCheckTheSame(number1 As Double, number2 As Double, Optional Digits As Integer = 12) As Boolean
If (number1 - number2) ^ 2 < (10 ^ -Digits) ^ 2 Then
dblCheckTheSame = True
Else
dblCheckTheSame = False
End If
End Function
Appelez-le avec:
MsgBox dblCheckTheSame(1.2345, 1.23456789)
MsgBox dblCheckTheSame(1.2345, 1.23456789, 4)
MsgBox dblCheckTheSame(1.2345678900001, 1.2345678900002)
MsgBox dblCheckTheSame(1.2345678900001, 1.2345678900002, 14)
Comme il a été souligné, de nombreux nombres décimaux ne peuvent pas être représentés avec précision sous forme de types à virgule flottante traditionnels. En fonction de la nature de votre espace de problèmes, il peut être préférable d’utiliser le type VBA décimal, qui peut représenter des nombres décimaux (base 10) avec une précision parfaite jusqu’à un certain point décimal. Ceci est souvent fait pour représenter de l'argent, par exemple lorsqu'une précision décimale à 2 chiffres est souvent souhaitée.
Dim a as Decimal
Dim b as Decimal
a = 0.15
b = 0.01
Le type de données Currency peut être une bonne alternative. Il gère des nombres relativement importants avec une précision fixe à quatre chiffres.
Travail-a-tour ?? Pas sûr que cela réponde à tous les scénarios, mais j'ai rencontré un problème en comparant les valeurs doubles arrondies dans VBA. Lorsque j'ai comparé des nombres qui semblaient identiques après l'arrondissement, VBA a déclenché la valeur false dans une instruction if-then compare. Mon correctif était d’exécuter deux conversions, d’abord doubler en chaîne, puis chaîne à doubler, puis faire la comparaison.
Exemple simulé Je n'ai pas enregistré les chiffres exacts à l'origine de l'erreur mentionnée dans ce message, et les montants de mon exemple ne déclenchent pas le problème actuellement et sont destinés à représenter le type de problème.
Sub Test_Rounded_Numbers()
Dim Num1 As Double
Dim Num2 As Double
Let Num1 = 123.123456789
Let Num2 = 123.123467891
Let Num1 = Round(Num1, 4) '123.1235
Let Num2 = Round(Num2, 4) '123.1235
If Num1 = Num2 Then
MsgBox "Correct Match, " & Num1 & " does equal " & Num2
Else
MsgBox "Inccorrect Match, " & Num1 & " does not equal " & Num2
End If
'Here it would say that "Inccorrect Match, 123.1235 does not equal 123.1235."
End Sub
Sub Fixed_Double_Value_Type_Compare_Issue()
Dim Num1 As Double
Dim Num2 As Double
Let Num1 = 123.123456789
Let Num2 = 123.123467891
Let Num1 = Round(Num1, 4) '123.1235
Let Num2 = Round(Num2, 4) '123.1235
'Add CDbl(CStr(Double_Value))
'By doing this step the numbers
'would trigger if they matched
'100% of the time
If CDbl(CStr(Num1)) = CDbl(CStr(Num2)) Then
MsgBox "Correct Match"
Else
MsgBox "Inccorrect Match"
End If
'Now it says Here it would say that "Correct Match, 123.1235 does equal 123.1235."
End Sub