Je suis tombé sur cette question SO qui demandait un moyen pour convertir des valeurs hexadécimales plus grandes en une valeur numérique positive:
?Val("&H8000") -32768 Val("&HFFFF") -1
Ma réponse impliquait ditérer les chiffres de la chaîne un par un, et de calculer leur valeur respective dans le résultat:
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
Cela fonctionne, mais je peux » t aide à penser que jai fait quelque chose de stupidement trop compliqué pour quelque chose qui devrait être assez simple.
Il ya « une meilleure façon, nest-ce pas?
Commentaires
Réponse
Daprès ce que je peux dire, une chaîne commençant par &H
est un littéral hexadécimal.
Il existe un nombre de fonctions de conversion qui peuvent convertir une expression au type souhaité.
Il devrait donc être simplement, selon le type souhaité:
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
Devise vs Double
Valeur entière positive maximale représentable avec précision:
-
&H0020000000000000
(9,007,199,254,740,992) pour Double ( IEEE 754 binaire64 ) -
&H000346DC5D638865
(922 337 203 685 477) pour Devise
Alors pourquoi utiliser Currency
sur Double
alors que ce dernier fonctionne pour une plus grande plage dentiers?
Currency
est toujours précis. Si nous dépassons une valeur de Currency
, nous obtenons une erreur. Si nous dépassons la valeur entière maximale représentable dun double, nous obtenons une valeur entière approximative:
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, "#")
Le résultat de cet exemple est:
Double before: 9007199254740990 after: 9007199254740990
Et puis un run-time error "6": Overflow
qui est génial si vous veulent éviter les erreurs darrondi. Maintenant, MSDN affirme que Double
est
stocké sous forme de nombre à virgule flottante IEEE 64 bits (8 octets)
mais si vous « avez lu quelque chose sur le IEEE 754 binary64 , vous devriez être un peu surpris par le résultat de lexemple. Le maximum réel est &H00038D7EA4C68000
(1 000 000 000 000 000).
Commentaires
- Génial! Jai ' lié à cette réponse sur une modification de ma réponse SO 🙂
- Jai développé le bit sur
Currency
vsDouble
un peu et jai découvert quelque chose dintéressant. - que diriez-vous de
doubleMax + doubleMax
jeter un erreur de débordement? - @Meehow Je viens de le tester et apparemment
Double
dans VBA déborde. Mais il ' est toujours pas possible de déborder si le résultat analysé est un entier. Je ' je suis content de ne pas ' Je nai pas besoin de travailler avec cette langue. - La façon idiomatique correcte de le faire est dutiliser lune des fonctions de conversion intégrées, comme @Meehow la commenté sur lOP – Je ne ' ne sais pas quel brainfart ma poussé à écrire cette fonction …
Short
,Integer
,Long
,UShort
,UInteger
,ULong
, ouDecimal
.Cdbl("&HFFFF")
?CDbl
est faux pour ce scénario.