Natknąłem się na to pytanie SO , które pytało o sposób aby przekonwertować większe wartości szesnastkowe na dodatnią wartość liczbową:
?Val("&H8000") -32768 Val("&HFFFF") -1
Moja odpowiedź polegała na iterowaniu kolejnych cyfr w ciągu i przeliczaniu ich wartości na wynik:
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
Działa, ale mogę ” nie pomyśleć, że zrobiłem coś głupio zbyt skomplikowanego dla czegoś, co powinno być całkiem proste.
Jest lepszy sposób, prawda?
Komentarze
Odpowiedź
Z tego, co mogę powiedzieć, że ciąg znaków zaczynający się od &H
to literał szesnastkowy.
Istnieje liczba funkcji konwersji , które mogą konwertować wyrażenie na żądany typ.
Więc powinno być po prostu, w zależności od pożądanego typu:
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
Waluta a podwójna
Maksymalna dokładna dodatnia liczba całkowita:
-
&H0020000000000000
(9,007,199,254,740,992) dla Double ( IEEE 754 binary64 ) -
&H000346DC5D638865
(922,337,203,685,477) dla Waluta
Po co więc używać Currency
zamiast Double
, kiedy to drugie działa dla większego zakresu liczb całkowitych?
jest zawsze dokładne. Jeśli przepełnimy wartość Currency
, otrzymamy błąd. Jeśli przepełnimy maksymalną możliwą do reprezentacji wartość całkowitą podwójną, otrzymamy przybliżoną wartość całkowitą:
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, "#")
Wynik tego przykładu to:
Double before: 9007199254740990 after: 9007199254740990
A następnie run-time error "6": Overflow
, co jest świetne, jeśli chcą uniknąć błędów zaokrągleń. Teraz oświadczenia MSDN Double
są
przechowywane jako 64-bitowa (8-bajtowa) liczba zmiennoprzecinkowa IEEE
ale jeśli czytałeś cokolwiek o IEEE 754 binary64 , powinieneś nieco zaskoczony wynikiem z przykładu. Rzeczywiste maksimum to &H00038D7EA4C68000
(1 000 000 000 000 000).
Komentarze
- Świetnie! ' połączyłem się z tą odpowiedzią podczas edycji mojej odpowiedzi SO 🙂
- Rozwinąłem trochę o
Currency
vsDouble
trochę i odkryłem coś interesującego. - co powiesz na
doubleMax + doubleMax
rzucenie błąd przepełnienia? - @Meehow Właśnie go przetestowałem i najwyraźniej
Double
w VBA powoduje przepełnienie. Ale ' s nadal nie można przepełnić, jeśli przetworzony wynik jest liczbą całkowitą. ' cieszę się, że nie ' nie muszę pracować z tym językiem. - Prawidłowym, idiomatycznym sposobem na to jest użycie jednej z wbudowanych funkcji konwersji, jak @Meehow skomentował OP – Nie ' nie wiem, co spowodowało bicie mózgu, że napisałem tę funkcję …
Short
,Integer
,Long
,UShort
,UInteger
,ULong
lubDecimal
.Cdbl("&HFFFF")
?CDbl
jest błędne w tym scenariuszu.