M-am împiedicat de această întrebare SO care întreba despre un mod pentru a converti valori hexagonale mai mari într-o valoare numerică pozitivă:
?Val("&H8000") -32768 Val("&HFFFF") -1
Răspunsul meu a presupus iterarea cifrelor șirului una câte una și calcularea valorii respective în rezultat:
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
Funcționează, dar pot ” Nu mă gândesc că am făcut ceva stupid prea complicat pentru ceva care ar trebui să fie destul de simplu.
Există o modalitate mai bună, nu există?
Comentarii
Răspuns
Din ceea ce pot spune un șir care începe cu &H
este un literal hexagonal.
Există un număr număr de funcții de conversie care poate converti o expresie la tipul dorit.
Deci ar trebui să fie pur și simplu, în funcție de tipul dorit:
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
Monedă vs Dublu
Valoarea maximă a numărului întreg pozitiv reprezentabil cu precizie:
-
&H0020000000000000
(9.007.199.254.740.992) pentru Double ( IEEE 754 binary64 ) -
&H000346DC5D638865
(922.337.203.685.477) pentru Monedă
Deci, de ce să folosiți Currency
peste Double
atunci când acesta din urmă funcționează pentru o gamă mai mare de numere întregi?
este întotdeauna corect. Dacă depășim o valoare Currency
vom obține o eroare. Dacă depășim valoarea maximă întreagă reprezentabilă a unui dublu, obținem o valoare întreagă aproximativă:
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, "#")
Rezultatul acestui exemplu este:
Double before: 9007199254740990 after: 9007199254740990
Și apoi un run-time error "6": Overflow
care este minunat dacă doriți să evitați erorile de rotunjire. Acum, revendicările MSDN Double
este
stocat ca număr cu virgulă mobilă IEEE pe 64 de biți (8 octeți)
dar dacă ați citit ceva despre IEEE 754 binary64 ar trebui să fiți un pic surprins de rezultatul din exemplu. Maximul real este &H00038D7EA4C68000
(1.000.000.000.000.000).
Comentarii
- Minunat! Am ' legat de acest răspuns într-o editare la răspunsul meu SO 🙂
- Am extins bitul despre
Currency
vsDouble
puțin și am descoperit ceva interesant. - ce zici de
doubleMax + doubleMax
aruncând un eroare de revărsare? - @Meehow Tocmai a testat-o și aparent
Double
în VBA se revarsă. Dar ' este încă nu este posibil să depășesc dacă rezultatul analizat este un număr întreg. Mă ' mă bucur că nu nu trebuie să funcționeze cu acest limbaj. - Modul corect, idiomatic de a face acest lucru este să folosiți una dintre funcțiile de conversie încorporate, așa cum a comentat @Meehow despre OP – Nu ' nu știu ce brainfart m-a determinat să scriu chiar această funcție …
Short
,Integer
,Long
,UShort
,UInteger
,ULong
, sauDecimal
.Cdbl("&HFFFF")
?CDbl
este greșit pentru acest scenariu.