Pergunta

Eu tenho problemas comparando 2 double no Excel VBA

supor que eu tenho o seguinte código

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

Depois de algumas manipulações sobre b, b é agora igual a 0,6

No entanto, a imprecisão relacionada com o tipo de dados duplo me dá dor de cabeça por causa

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

Você sabe como posso remover a imprecisão de fuga do tipo duplo?

Foi útil?

Solução

Você não pode comparar valores de ponto flutuante de igualdade. Veja este artigo em " Comparando números de ponto flutuante " para uma discussão sobre como lidar com o erro intrínseco.

Não é tão simples como comparar a uma margem de erro constante se você não sabe ao certo o que a gama absoluta dos carros alegóricos é de antemão.

Outras dicas

Se você estiver indo para fazer isso ....

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

você precisa adicionar a função rodada em sua declaração IF assim ...

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

Veja também aqui para referência adicional Microsoft.

Nunca é sábio comparar duplas na igualdade.

Alguns valores decimais mapear para várias representações de ponto flutuante. Então, um 0.6 nem sempre é igual à outra 0,6.

Se subtrairmos um do outro, nós provavelmente obter algo como 0,00000000051.

Podemos agora definir a igualdade como tendo uma diferença menor que uma certa margem de erro.

Aqui é uma função simples que eu escrevi:

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

chamá-lo com:

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 já foi referido, muitos números decimais não pode ser representado exatamente como tipos de ponto flutuante tradicionais. Dependendo da natureza do seu espaço de problema, você pode ser melhor fora de usar o tipo Decimal VBA que pode representar números decimais (base 10) com uma precisão perfeita até um certo ponto decimal. Isto é feito frequentemente para representar o dinheiro, por exemplo, onde a precisão decimal de 2 dígitos é muitas vezes desejado.

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

O tipo de dados Moeda pode ser uma boa alternativa. Ele lida com um número relativamente grande com uma precisão de quatro dígitos fixo.

Work-a-redonda ?? Não tenho certeza se isso vai responder a todas as situações, mas eu tive um problema de comparar os valores duplas arredondadas em VBA. Quando eu em comparação com os números que pareciam ser idênticas após o arredondamento, VBA provocaria falso em uma declaração if-then comparar. Minha solução foi correr duas conversões, primeiro casal de corda, em seguida, cordas para dobrar, e então fazer a comparação.

Simulado Exemplo Eu não gravar os números exatos que causou o erro mencionado neste post, e os montantes em meu exemplo não desencadear o problema atualmente e se destinam a representar o 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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top