Eu descobri esta questão SO que estava perguntando sobre uma maneira para converter valores hexadecimais maiores em um valor numérico positivo:

?Val("&H8000") -32768 Val("&HFFFF") -1 

Minha resposta envolveu iterar os dígitos da string um por um e calcular seus respectivos valores no resultado:

Function ConvertHex(ByVal value As String) As Double If Left(value, 2) = "&H" Then value = Right(value, Len(value) - 2) End If Dim result As Double Dim i As Integer, j As Integer For i = Len(value) To 1 Step -1 Dim digit As String digit = Mid$(value, i, 1) result = result + (16 ^ j) * Val("&H" & digit) j = j + 1 Next ConvertHex = result End Function 

Funciona, mas eu consigo ” não deixe de pensar que fiz algo estupidamente complicado demais para algo que deveria ser bem simples.

Há uma maneira melhor, não é?

Comentários

  • Eu ' estou confuso quanto ao que você deseja realizar. " Duplo " geralmente significa um número de ponto flutuante de 64 bits. Ainda assim, seu texto diz que você deseja um " valor numérico positivo ", mas seus exemplos parecem mostrar assinados Inteiros de 16 bits (geralmente chamados de " curtos "). Além disso, parece que apenas números inteiros podem ser representados na string hexadecimal, então o tipo de retorno deve ser Short, Integer, Long, UShort, UInteger, ULong ou Decimal.
  • @ 200_success Há ' s apenas um conjunto muito limitado de tipos de dados em VBA. Nenhum tipo sem sinal …
  • Mat, o que ' há de errado com Cdbl("&HFFFF")?
  • @Meehow veja a atualização de minha resposta para saber por que eu acho que CDbl é errado para este cenário.
  • @Meehow isso é exatamente o que eu quis dizer com " eu ' fiz algo estupidamente complicado demais para algo que deveria ser muito simples " 😉

Resposta

Pelo que posso dizer, uma string começando com &H é um literal hexadecimal.

Existe um número de funções de conversão que podem converter uma expressão para o tipo desejado.

Então, deve ser simplesmente, dependendo do tipo desejado:

Function ConvertHex(ByVal value As String) As Currency Dim result As Currency result = CCur(value) If result < 0 Then "Add two times Int32.MaxValue and another 2 for the overflow "Because the hex value is apparently parsed as a signed Int64/Int32 result = result + &H7FFFFFFF + &H7FFFFFFF + 2 End If ConvertHex = result End Function 

Moeda vs duplo

Valor inteiro positivo máximo representável com precisão:

Então, por que usar Currency em vez de Double quando o último funciona para um intervalo maior de inteiros?

Currency é sempre preciso. Se estourarmos um valor Currency, obteremos um erro. Se estourarmos o valor inteiro representável máximo de um double, obteremos um valor inteiro aproximado:

Dim doubleMax As Double Dim doubleAfter As Double doubleMax = CDbl("&H0020000000000000") doubleAfter = doubleMax + 1 MsgBox "Double before: " & Format(doubleMax, "#") & vbNewLine & "after: " & Format(doubleAfter, "#") Dim currencyMax As Currency Dim currencyAfter As Currency currencyMax = CCur("&H000346DC5D638865") currencyAfter = currencyMax + 1 MsgBox "Currency before: " & Format(currencyMax, "#") & vbNewLine & "after: " & Format(currencyAfter, "#") 

A saída deste exemplo é:

 Double before: 9007199254740990 after: 9007199254740990  

E então um run-time error "6": Overflow que é ótimo se você deseja evitar erros de arredondamento. Agora, o MSDN afirma que Double é

armazenado como número de ponto flutuante IEEE de 64 bits (8 bytes)

mas se você leu qualquer coisa sobre o IEEE 754 binário64 , você deve ser um pouco surpreso com a saída do exemplo. O máximo real é &H00038D7EA4C68000 (1.000.000.000.000.000).

Comentários

  • Incrível! Eu ' vinculei a esta resposta em uma edição da minha resposta SO 🙂
  • Eu expandi um pouco sobre Currency vs Double um pouco e descobriu algo interessante.
  • que tal doubleMax + doubleMax jogar um erro de estouro?
  • @Meehow Acabei de testar e, aparentemente, Double no VBA transborda. Mas ' ainda está não é possível estourar se o resultado analisado for um número inteiro. I ' Fico feliz por não ' não preciso trabalhar com esse idioma.
  • A maneira idiomática correta de fazer isso é usar uma das funções de conversão integradas, como @Meehow comentou no OP – Eu não ' não sei o que brainfart me fez escrever esta função …

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *