Ik kwam deze SO-vraag tegen die vroeg over een manier om grotere hexadecimale waarden om te zetten in een positieve numerieke waarde:
?Val("&H8000") -32768 Val("&HFFFF") -1
Mijn antwoord betrof het een voor een itereren van de tekenreekscijfers en het berekenen van hun respectieve waarde in het resultaat:
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
Het werkt, maar ik kan ” Ik denk niet dat ik “iets stompzinnigs te ingewikkelds heb gedaan voor iets dat vrij eenvoudig zou moeten zijn.
Er is een betere manier, nietwaar?
Opmerkingen
Antwoord
Van wat ik kan zien aan een string die begint met &H
is een hexadecimale letter.
Er bestaat een aantal conversiefuncties die een uitdrukking kunnen converteren naar het gewenste type.
Dus het zou eenvoudig moeten zijn, afhankelijk van het gewenste type:
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
Valuta versus dubbel
Maximaal nauwkeurig representeerbare positieve gehele waarde:
-
&H0020000000000000
(9,007,199,254,740,992) voor Dubbel ( IEEE 754 binary64 ) -
&H000346DC5D638865
(922.337.203.685.477) voor Valuta
Dus waarom zou je Currency
boven Double
gebruiken als de laatste werkt voor een groter bereik van gehele getallen?
Currency
is altijd nauwkeurig. Als we een Currency
-waarde overschrijden, krijgen we een foutmelding. Als we de maximaal representeerbare integerwaarde van een dubbel overschrijden, krijgen we een geschatte integerwaarde:
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, "#")
De output van dit voorbeeld is:
Double before: 9007199254740990 after: 9007199254740990
En dan een run-time error "6": Overflow
wat geweldig is als je afrondingsfouten willen voorkomen. Nu claimt MSDN Double
is
opgeslagen als IEEE 64-bit (8-byte) drijvende-kommagetal
maar als je “iets hebt gelezen over de IEEE 754 binary64 , zou je dat moeten zijn een beetje verbaasd over de uitvoer van het voorbeeld. Het werkelijke maximum is &H00038D7EA4C68000
(1.000.000.000.000.000).
Opmerkingen
- Geweldig! Ik ' heb naar dit antwoord gelinkt bij een bewerking van mijn SO-antwoord 🙂
- Ik heb het stukje over vs
Double
een beetje en ontdekte iets interessants. - wat dacht je van
doubleMax + doubleMax
het gooien van een overloopfout? - @Meehow Net getest en blijkbaar loopt
Double
in VBA over. Maar het ' is nog steeds kan niet worden overschreden als het ontlede resultaat een geheel getal is. Ik ' ben blij dat ik niet ' hoeft niet met die taal te werken. - De juiste, idiomatische manier om dit te doen is door een van de ingebouwde conversiefuncties te gebruiken, zoals @Meehow opmerkte op het OP – Ik weet niet ' welke hersenscheurt me ertoe bracht om deze functie zelfs maar te schrijven …
Short
,Integer
zijn,Long
,UShort
,UInteger
,ULong
, ofDecimal
.Cdbl("&HFFFF")
?CDbl
verkeerd is voor dit scenario.