Pregunta

Tengo problemas para comparar 2 dobles en Excel VBA

supongamos que tengo el siguiente código

Dim a as double
Dim b as double
a = 0.15
b = 0.01

Después de algunas manipulaciones en b, b ahora es igual a 0.6

sin embargo, la imprecisión relacionada con el doble tipo de datos me da dolor de cabeza porque

if a = b then
 //this will never trigger
end if

¿Sabe cómo puedo eliminar la imprecisión final en el tipo doble?

¿Fue útil?

Solución

No se pueden comparar valores de punto flotante por igualdad. Consulte este artículo en " Comparación de punto flotante números " para una discusión de cómo manejar el error intrínseco.

No es tan simple como compararlo con un margen de error constante a menos que sepa con seguridad cuál es el rango absoluto de los flotadores de antemano.

Otros consejos

si vas a hacer esto ....

Dim a as double  
 Dim b as double  
 a = 0.15  
 b = 0.01

debe agregar la función de redondeo en su declaración IF de esta forma ...

  If Round(a,2) = Round(b,2) Then   
     //code inside block will now trigger.
  End If  

Consulte también aquí para obtener referencias adicionales de Microsoft .

Nunca es aconsejable comparar dobles en igualdad.

Algunos valores decimales se asignan a varias representaciones de punto flotante. Entonces, un 0.6 no siempre es igual al otro 0.6.

Si restamos uno del otro, probablemente obtengamos algo como 0.00000000051.

Ahora podemos definir la igualdad como una diferencia menor que un cierto margen de error.

Aquí hay una función simple que escribí:

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

Llámalo 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)

Como se ha señalado, muchos números decimales no se pueden representar precisamente como tipos tradicionales de punto flotante. Dependiendo de la naturaleza de su espacio problemático, puede ser mejor usar el tipo Decimal VBA que puede representar números decimales (base 10) con una precisión perfecta hasta cierto punto decimal. Esto se hace a menudo para representar el dinero, por ejemplo, donde a menudo se desea una precisión decimal de 2 dígitos.

Dim a as Decimal
Dim b as Decimal
a = 0.15
b = 0.01

El tipo de datos de Moneda puede ser una buena alternativa. Maneja números relativamente grandes con una precisión fija de cuatro dígitos.

¿Trabajar una ronda? No estoy seguro de si esto responderá a todos los escenarios, pero me encontré con un problema al comparar valores dobles redondeados en VBA. Cuando comparé con números que parecían ser idénticos después del redondeo, VBA activaría falso en una declaración de comparación si-entonces. Mi solución fue ejecutar dos conversiones, primero doble a cadena, luego cadena a doble y luego hacer la comparación.

Ejemplo simulado No registré los números exactos que causaron el error mencionado en esta publicación, y las cantidades en mi ejemplo no desencadenan el problema actualmente y están destinados a representar el tipo de 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top