Confronta il doppio nel problema di precisione VBA
-
04-07-2019 - |
Domanda
Ho difficoltà a confrontare 2 doppie in Excel VBA
supponi di avere il seguente codice
Dim a as double
Dim b as double
a = 0.15
b = 0.01
Dopo alcune manipolazioni su b, b ora è uguale a 0,6
tuttavia l'imprecisione relativa al doppio tipo di dati mi dà mal di testa perché
if a = b then
//this will never trigger
end if
Sai come posso rimuovere l'imprecisione finale sul doppio tipo?
Soluzione
Non è possibile confrontare i valori in virgola mobile per l'uguaglianza. Consulta questo articolo su " Confronto di virgola mobile numeri " per una discussione su come gestire l'errore intrinseco.
Non è semplice come confrontarlo con un margine di errore costante a meno che non si sappia con certezza quale sia la gamma assoluta dei float.
Altri suggerimenti
se hai intenzione di farlo ....
Dim a as double
Dim b as double
a = 0.15
b = 0.01
devi aggiungere la funzione round nell'istruzione IF in questo modo ...
If Round(a,2) = Round(b,2) Then
//code inside block will now trigger.
End If
Vedi anche qui per ulteriori riferimenti Microsoft .
Non è mai saggio confrontare i doppi sull'uguaglianza.
Alcuni valori decimali sono associati a diverse rappresentazioni in virgola mobile. Quindi uno 0.6 non è sempre uguale all'altro 0.6.
Se sottraggiamo l'uno dall'altro, probabilmente otteniamo qualcosa come 0.00000000051.
Ora possiamo definire l'uguaglianza come avere una differenza minore di un certo margine di errore.
Ecco una semplice funzione che ho scritto:
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
Chiamalo con:
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)
Come è stato sottolineato, molti numeri decimali non possono essere rappresentati esattamente come tipi tradizionali a virgola mobile. A seconda della natura del tuo spazio problematico, potresti stare meglio usando il tipo VBA decimale che può rappresentare numeri decimali (base 10) con precisione perfetta fino a un certo punto decimale. Questo viene spesso fatto per rappresentare denaro, ad esempio quando si desidera spesso la precisione decimale a 2 cifre.
Dim a as Decimal
Dim b as Decimal
a = 0.15
b = 0.01
Il tipo di dati Valuta può essere una buona alternativa. Gestisce numeri relativamente grandi con una precisione fissa di quattro cifre.
Il lavoro-a-tutto l'?? Non sono sicuro se questo risponderà a tutti gli scenari, ma ho riscontrato un problema nel confrontare valori doppi arrotondati in VBA. Quando ho confrontato con numeri che sembravano essere identici dopo l'arrotondamento, VBA avrebbe attivato false in un'istruzione if-then compare. La mia correzione era di eseguire due conversioni, prima il doppio in stringa, quindi la stringa in doppio, quindi fare il confronto.
Esempio simulato Non ho registrato i numeri esatti che hanno causato l'errore menzionato in questo post e gli importi nel mio esempio non attivano il problema attualmente e sono destinati a rappresentare il tipo di problema.
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