Jeg snublet på dette SO spørsmålet som spurte om en måte for å konvertere større hexverdier til en positiv numerisk verdi:
?Val("&H8000") -32768 Val("&HFFFF") -1
Svaret mitt innebar å itere strengsifrene en etter en, og beregne deres respektive verdi til resultatet:
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
Det fungerer, men jeg kan » Jeg kan ikke tenke på at jeg har gjort noe dumt for komplisert for noe som skal være ganske enkelt.
Det er en bedre måte, er det ikke?
Kommentarer
Svar
Fra det jeg kan fortelle en streng som begynner med &H
er en hekseliteral.
Det finnes et antall konverteringsfunksjoner som kan konvertere et uttrykk til ønsket type.
Så det skal rett og slett være, avhengig av ønsket 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 dobbel
Maksimalt nøyaktig representativt positivt heltall:
-
&H0020000000000000
(9,007,199,254,740,992) for Dobbelt ( IEEE 754 binary64 ) -
&H000346DC5D638865
(922,337,203,685,477) for Valuta
Så hvorfor bruke Currency
over Double
når sistnevnte fungerer for et større utvalg av heltall?
Currency
er alltid nøyaktig. Hvis vi overløper en Currency
-verdi, får vi en feil. Hvis vi overløper den maksimale representable heltallverdien til en dobbel, får vi en omtrentlig heltallverdi:
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, "#")
Resultatet av dette eksemplet er:
Double before: 9007199254740990 after: 9007199254740990
Og så en run-time error "6": Overflow
som er flott hvis du ønsker å unngå avrundingsfeil. Nå hevder MSDN at Double
er
lagret som IEEE 64-biters (8-byte) flytnummer
men hvis du har lest noe om IEEE 754 binary64 , bør du være litt overrasket over resultatet fra eksemplet. Det faktiske maksimumet er &H00038D7EA4C68000
(1.000.000.000.000.000.000).
Kommentarer
- Kjempebra! Jeg ' har koblet til dette svaret på en redigering av mitt SO-svar 🙂
- Jeg utvidet litt om
Currency
vsDouble
litt og oppdaget noe interessant. - hva med
doubleMax + doubleMax
å kaste et overflow error? - @Meehow Bare testet den og tilsynelatende overløper
Double
i VBA. Men den ' er fortsatt ikke mulig å løpe over hvis det analyserte resultatet er et heltall. Jeg ' er glad for at jeg ikke ' t må jobbe med det språket. - Den riktige, idiomatiske måten å gjøre dette på er å bruke en av de innebygde konverteringsfunksjonene, som @Meehow kommenterte OP – Jeg vet ikke ' hva brainfart fikk meg til å skrive denne funksjonen …
Short
,Integer
,Long
,UShort
,UInteger
,ULong
, ellerDecimal
.Cdbl("&HFFFF")
?CDbl
er feil i dette scenariet.