Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Decimal to Hex 2

Status
Not open for further replies.

sacsac

Programmer
Dec 10, 2000
182
GB
I know that it's easy to convert a decimal value to Hex using:

HexValue = Hex(DecimalValue)

That's fine, until I have a very large decimal value like:

123456789877754 (which is basically of DataType Variant, with a CDec conversion)

This causes an overflow when trying to convert to Hex.

I've trawled through various threads, which seem to mainly deal with the issues of Hex to Decimal (and which I have under control!)

Any ideas?
 
Howdy!

Have a try with this little snippet:

Code:
dim hexcod as string, tmp as long, theVal as String

tmp=DecValue 'your decimal variable
        Do While tmp > 0
            theVal = tmp Mod 16
            If theVal > 9 Then
                theVal = Chr(CInt(theVal) + 55)
            End If
            hexcod = hexcod & theVal
            tmp = tmp \ 16
        Loop
        hexcod = StrReverse(hexcod)

Hope this helps!
:)

Cheers,
Andy

[blue]Help us, join us, participate
IAHRA - International Alliance of Human Rights Advocates[/blue]
 
Sure. I wrote Hex2Dec and Dec2Hex functions to handle large numbers ready for posting in thread222-1289620, but things got a little out of hand there so I never got around to it. The code is on my home PC, so won't be able to post it until later
 
Thanks MakeItSo. Unfortunately this still bombs out at the line:
theVal = tmp Mod 16

if tmp is a value greater than the upper limit for a Long datatype. That's been my problem all along!

I'll look forward to seeing the functions which you have written Strongm, to see how they work
 
You can simply use the traditional 'long division' algorithm, dividing by 16 and converting remainders from 10 to 15 into the corresponding letters as you go

________________________________________________________________
If you want to get the best response to a question, please check out FAQ222-2244 first.
'If we're supposed to work in Hex, why have we only got A fingers?'
Drive a Steam Roller
 
You're welcome [smile]

________________________________________________________________
If you want to get the best response to a question, please check out FAQ222-2244 first.
'If we're supposed to work in Hex, why have we only got A fingers?'
Drive a Steam Roller
 
Code:
[blue]Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
 
' Low math and string solution
Public Function Dec2Hex(ByVal strDec As Variant) As String
    Dim mybyte(0 To 19) As Byte
    Dim lp As Long
    
    CopyMemory mybyte(0), ByVal VarPtr(CDec(strDec)), 16
    
    ' Quick reorganise so we can then just step through the entire thing in one loop
    For lp = 7 To 4 Step -1
        mybyte(12 + lp) = mybyte(lp)
    Next
    
    ' Build the hex string
    For lp = 19 To 8 Step -1
        If (Not Len(Dec2Hex) And mybyte(lp) <> 0) Or Len(Dec2Hex) Then
            Dec2Hex = Dec2Hex & Format(Hex(mybyte(lp)), IIf(Len(Dec2Hex), "00", "0"))
        End If
    Next
    
End Function

Public Function Hex2Dec(strSource As String) As Variant
    Dim lp As Long
    
    Hex2Dec = "Cannot convert"
    
    If Len(strSource) Mod 2 Then strSource = "0" & strSource ' pad string
    
    If Len(strSource) <= 24 Then ' Make sure we don't overflow the Decimal variant
        Hex2Dec = CDec(0)
        For lp = 1 To Len(strSource) Step 2
            Hex2Dec = Hex2Dec * 256 + Val("&h" & Mid$(strSource, lp, 2))
        Next
    End If
    
End Function[/blue]
 
Thanks very much strongm - I'll try this code.
 
Hi again strongm! I thought that your code for Dec2Hex was fine - until I tested some really large numbers. If you input decimal value 999999999 it returns 3B00C9FF, but I believe that the correct hex value is 3B9AC9FF. I've now written my own code, which seems to work correctly. Here it is:

Private Function DecToHex(ByVal DecVal As String) As String

Dim vntRemainder As Variant
Dim vntInteger As Variant
Dim strHex() As String
Dim intC As Integer
Dim strTemp As String

On Error GoTo Handler

Erase strHex
intC = 0
vntInteger = CDec(DecVal)
vntRemainder = CDec(DecVal)


Do Until vntInteger = 0

vntRemainder = CDec(CDec(vntInteger) - CDec(16 * CDec(Int(CDec(vntInteger / 16)))))

Select Case vntRemainder
Case 15
strTemp = "f"
Case 14
strTemp = "e"
Case 13
strTemp = "d"
Case 12
strTemp = "c"
Case 11
strTemp = "b"
Case 10
strTemp = "a"
Case Else
strTemp = CStr(CDec(vntRemainder) Mod 16)

End Select


vntInteger = CDec(Int(CDec(vntInteger / 16)))

intC = intC + 1
ReDim Preserve strHex(1 To intC)
strHex(intC) = strTemp

Loop


DecToHex = ""
For intC = UBound(strHex) To 1 Step -1
DecToHex = DecToHex & strHex(intC)
Next

Exit Function


Handler:
MsgBox "Error Num: " & Err.Number & vbCrLf & Err.Description, , Me.Caption
Exit Function


End Function
 
Yep, my fault; I tried to compress the logic down too much in the line

Dec2Hex = Dec2Hex & Format(Hex(mybyte(lp)), IIf(Len(Dec2Hex), "00", "0"))

Change it to my original

Dec2Hex = Dec2Hex & IIf(Len(Dec2Hex), Right$("0" & Hex(mybyte(lp)), 2), Hex(mybyte(lp)))

and all should be well
 
Just thought that you'd like to know that your amended code is spot on and I am now getting the expected results!
Thanks for your help.
 
You may also try this simpler version.
___
[tt]
Function Dec2Hex(ByVal Dec As Variant) As String
Dim V As Variant
Do
V = Dec / 16
Dec2Hex = Hex$((V - Int(V)) * 16) & Dec2Hex
Dec = Int(V)
Loop While Dec
End Function[/tt]
 
But which oddly gets 79,228,162,514,264,337,593,543,950,335 wrong
 
Yes, I knew this function would bug for very large numbers reaching the limit of Decimal due to roundoff errors, but no function is perfect. Try passing 0 to your function.
 
No, no - I use the word 'oddly' deliberately. As long as you pass a CDec'd variant as the parameter (or add a Dec=Cdec(Dec) line to the function) your code works absolutely fine with no rounding errors. It only gets 79,228,162,514,264,337,593,543,950,335 wrong, and I don't think that is a rounding error









(And my function only gets zero 'wrong' because it is overly zealous in suppressing leading zeros ...)
 
>It only gets 79,228,162,514,264,337,593,543,950,335 wrong,
>and I don't think that is a rounding error

Actually, it gets many large numbers wrong, as I stated above, not only the one you mentioned, and the reason is actually the floating point / rounding errors resulting due to the division, [tt]V = Dec / 16[/tt].

Try running the following code with my function.
___
[tt]
Private Sub Form_Load()
Dim V As Variant, N As Long
V = CDec("79228162514264337593543950335")
For N = 1 To 16
Debug.Print V, Dec2Hex(V)
V = V - 1
Next
End
End Sub[/tt]
___

Here's the result. You can see wrong conversion at many places.
[tt]
79228162514264337593543950335 FFFFFFFFFFFFFFFFFFFFFFFE
79228162514264337593543950334 FFFFFFFFFFFFFFFFFFFFFFFE
79228162514264337593543950333 FFFFFFFFFFFFFFFFFFFFFFFD
79228162514264337593543950332 FFFFFFFFFFFFFFFFFFFFFFFD
79228162514264337593543950331 FFFFFFFFFFFFFFFFFFFFFFFB
79228162514264337593543950330 FFFFFFFFFFFFFFFFFFFFFFFA
79228162514264337593543950329 FFFFFFFFFFFFFFFFFFFFFFFA
79228162514264337593543950328 FFFFFFFFFFFFFFFFFFFFFFF8
79228162514264337593543950327 FFFFFFFFFFFFFFFFFFFFFFF6
79228162514264337593543950326 FFFFFFFFFFFFFFFFFFFFFFF6
79228162514264337593543950325 FFFFFFFFFFFFFFFFFFFFFFF5
79228162514264337593543950324 FFFFFFFFFFFFFFFFFFFFFFF3
79228162514264337593543950323 FFFFFFFFFFFFFFFFFFFFFFF3
79228162514264337593543950322 FFFFFFFFFFFFFFFFFFFFFFF2
79228162514264337593543950321 FFFFFFFFFFFFFFFFFFFFFFF2
79228162514264337593543950320 FFFFFFFFFFFFFFFFFFFFFFF0
[/tt]
This is my understanding about this error.

When 79228162514264337593543950335 is divided by 16, the actual result is 4951760157141521099596496895.9375. But as the result is stored in a Decimal variant, only 29 digits are preserved, due to the precision limits of Decimal. So the result stored in V is 4951760157141521099596496895.9.

Next, the fractional portion of the above number is evaluated as V - Int(V), which turns out to be 0.9 instead of 0.9375. This is multiplied by 16 which turns out to be 14.4 instead of 15. This is passed to the Hex$ function which returns E instead of F. 14.4 is rounded down to 14 by the Hex function.

As long as the result of division V = Dec / 16 does not fit in 29 digits, the output of the function would contain errors as shown above.
 
And there I was trying to defend your function, and you've gone and blown holes in it ...

You are, of course, correct
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top