[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

8-byte hex IEEE-754 to VB6 single-precision float needed asap!

Posted on 2005-04-16
10
Medium Priority
?
7,417 Views
Last Modified: 2011-10-03
Before you think you have the correct solution, please test it with this webpage first:
http://babbage.cs.qc.edu/courses/cs341/IEEE-754hex32.html

And, test your routine with this hex value: 4287A929 which SHOULD be converted to this decimal value: 67.830391 but my routine, and all those I've seen on the web, get 125.2863 instead.

I _have_ seen some of the other routines available, and they all do NOT work with this particular value. Why not? The one by _pit_ here on experts-exchange only accepts 4-byte hex values, and I'm not sure how to "fix" it to accept 8-byte hex values, so I don't even know if his works properly either.

Here is the code I am using. Can anyone please tell me what the bug is...why won't it convert the above hex value to the above correct decimal value? This is not my code, it is the code that has been floating (pardon the pun) around the web for years:

'
' function is getting passed an 8-byte IEEE hex value such as 4287A929
' and is supposed to return a value of 67.83039 but doesn't
'
Public Function SingleConv(whole As Variant) As Variant
Dim expnt, mantis, Psign As Boolean, result, multiplier, L, q, que
L = Len(whole)
If L < 8 Then
    whole = whole & String(8 - L, &H30) '"0"
End If
If L > 8 Then
    whole = Left(whole, 8)
End If
expnt = "&H" & Left(whole, 3)
If expnt And &H800 Then Psign = True Else Psign = False
expnt = (Val(expnt) And &H7F8) / 8 'shift right 3 places
expnt = "&H" & Hex(expnt)
mantis = "&H" & Right(whole, 6)
mantis = (Val(mantis) And &H7FFFFF) * 2  'convert to numerical and switch top bit off, shift left 1 position
mantis = Hex(mantis)             'stick back into var as hex
expnt = Val(expnt)
'translate expnt
expnt = expnt - &H7F
expnt = 2 ^ expnt
'translate mantis
result = 1
For q = 1 To 6
    que = "&H" & Mid(mantis, q, 1)
    que = Val(que)
    multiplier = 1 / 2 ^ (q * 4)
    result = result + (multiplier * que)
Next q
result = result * expnt
If Psign Then result = 0 - result
SingleConv = str(result)
End Function
0
Comment
Question by:mushu999
  • 4
  • 3
  • 3
10 Comments
 
LVL 32

Accepted Solution

by:
Erick37 earned 1600 total points
ID: 13799704
A Single data type is only 4 bytes.
The hex data 4287A929 is also 4 bytes.

Converting a 4 byte hex to a Single should be easy:


Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private Sub Command1_Click()

    Dim sngVal As Single
    Dim sHex As String
    Dim lVal As Long
   
    'Our Hex String
    sHex = "4287A929"
   
    'The value of the hex string
    lVal = Val("&h" & sHex)
   
    'Copy the bytes over to a Single data type
    Call CopyMemory(sngVal, lVal, 4)
   
    'Display the results
    MsgBox Format(sngVal, "0.000000")

End Sub
0
 
LVL 32

Expert Comment

by:Erick37
ID: 13799736
The 8 byte representation of 67.830391 is:
4050F525204AF923

And can be tested here:
http://babbage.cs.qc.edu/courses/cs341/IEEE-754hex64.html
0
 
LVL 4

Assisted Solution

by:rdwillett
rdwillett earned 400 total points
ID: 13799933
Add one commandbutton named Command1 and one textbox named Text1
Add the following code and type hexvalue in text1 and click command1

Private Function HextoIEEE754(HexValue As String) As Double
    Dim i As Integer
    Dim binvalue  As String
    Dim Sign As Integer
    Dim Exponent As Double
    Dim Mantissa As Double
    binvalue = ""
    For i = 1 To Len(HexValue)
        Select Case Mid$(HexValue, i, 1)
            Case "0"
                binvalue = binvalue & "0000"
            Case "1"
                binvalue = binvalue & "0001"
            Case "2"
                binvalue = binvalue & "0010"
            Case "3"
                binvalue = binvalue & "0011"
            Case "4"
                binvalue = binvalue & "0100"
            Case "5"
                binvalue = binvalue & "0101"
            Case "6"
                binvalue = binvalue & "0110"
            Case "7"
                binvalue = binvalue & "0111"
            Case "8"
                binvalue = binvalue & "1000"
            Case "9"
                binvalue = binvalue & "1001"
            Case "A"
                binvalue = binvalue & "1010"
            Case "B"
                binvalue = binvalue & "1011"
            Case "C"
                binvalue = binvalue & "1100"
            Case "D"
                binvalue = binvalue & "1101"
            Case "E"
                binvalue = binvalue & "1110"
            Case "F"
                binvalue = binvalue & "1111"
        End Select
    Next i
    If Mid(binvalue, 1, 1) = 0 Then Sign = 1 Else Sign = -1
    Exponent = GetExponent(Mid(binvalue, 2, 8))
    Mantissa = GetMantissa(Mid(binvalue, 10, 23))
    HextoIEEE754 = Sign * 2 ^ Exponent * Mantissa
End Function
Function GetExponent(binval As String) As Long
  Dim n As Integer
    n = Len(binval) - 1
    a = n
     Do While n > -1
        x = Mid(binval, ((a + 1) - n), 1)
        GetExponent = IIf((x = "1"), GetExponent + (2 ^ (n)), GetExponent)
        n = n - 1
     Loop
     GetExponent = GetExponent - 127
End Function
Private Function GetMantissa(binval As String) As Double
    Dim i As Integer
    Dim z As Double
    Dim result As Double
    Dim b As Integer
    result = 0
    For i = 1 To 23
        b = Int(Val(Mid$(binval, i, 1)))
        z = b * (1 / (2 ^ i))
        result = result + z
    Next i
    GetMantissa = 1 + result
End Function
Private Sub Command1_Click()
   MsgBox HextoIEEE754(Text1.Text)
End Sub
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:mushu999
ID: 13799936
Erick37, you are looking at the 64-bit answer. The 32-bit answer comes out correctly on that same web page. I will try your answer shortly. If it works correctly in all cases then you'll have earned the points. If not, then I hope others keep trying. I've wasted so much time on this stupid problem my head hurts!  :)
0
 
LVL 4

Expert Comment

by:rdwillett
ID: 13799947
Tested Erick's and it works fine actually great.  If you are going to use this program to convert a large number hexadecimals to IEEE754 (such as PLC values - Double Floating) then use his for sure.  If you need the exponent, sign, and mantissa use mine.  I originally wrote this code for PLC (AB, GE).  I will now use Ericks for PLCs because I don't need the exponent, sign, or mantissa.  
0
 
LVL 1

Author Comment

by:mushu999
ID: 13799983
Because it uses a memory move, I'm wondering how it actually works. It scares me to not understand the method being used, since it might break on an untested value later. This is being used in a program that must run 24x7 without crashing or errors...so far it has been doing awesome, but we just discovered that the algorithm I used for IEEE conversion has..ummm...flaws.....

Also, I retract my previous comment to Erick. I reread what he said, and I responded incorrectly. Indeed, I was not thinking straight regarding the 4-byte and 8-byte hex value sizes, since 8 bytes IS 64 bits! Good grief, I'm exhausted...so, forgive me Erick for my silly-sounding reply above.

I'd still like you to briefly explain why your routine works at all, and how it does the work. Seems like it depends on the CPU or perhaps DMA controller itself to "convert" the values in memory. Not sure if this is something to rely on--what if the user gets a new computer that doesn't exhibit the same hardware characteristics?
0
 
LVL 1

Author Comment

by:mushu999
ID: 13800004
I found the skinny on this CopyMemory thingy, from this URL, FWIW: http://vb.mvps.org/hardcore/html/bringyourhatchet.htm

CopyMemory: A Strange and Terrible Saga

Here’s the long, strange story of how the Win32 function for copying raw memory came to be called CopyMemory, even though there’s no such function in Visual Basic or in the Windows API.

It started when I first began searching for the Win32 equivalent of the Win16 hmemcpy function for use in Visual Basic version 4. No such thing—not even a note that the function might be obsolete. But…

The closest I could come up with was the CopyMemory function, which has exactly the same arguments and is documented the same as the old hmemcpy. Unfortunately, despite what you might read in Win32 documentation, there is no such thing as CopyMemory. You can search all the 32-bit DLLs with the DumpBin utility, but you won’t find any DLL containing CopyMemory. But…

If you search carefully through the Win32 C include files, you’ll turn up the following in WINBASE.H:

#define CopyMemory RtlCopyMemory
#define MoveMemory RtlMoveMemory
#define ZeroMemory RtlZeroMemory

This C equivalent of an alias indicates that CopyMemory is another name for a function called RtlCopyMemory. Don’t ask why; just check for RtlCopyMemory in KERNEL32.DLL. Again, nothing. More sleuthing in the Win32 include files reveals the reason. WINNT.H contains something like this:

#define RtlCopyMemory(dst, src, len) memcpy(dst, src, len)

In other words, RtlCopyMemory is an alias for the C memcpy function, but you can’t use memcpy or any other C library function from Basic. The documenta-tion is simply lying when it claims that CopyMemory is a Windows function rather than a C function. If it’s not exported from a DLL, you can’t call it. But… KERNEL32.DLL does contain an entry for RtlMoveMemory. If you check the Win32 documentation, you’ll see that MoveMemory does the same thing as CopyMemory except that it handles overlapped memory in a different fashion. I can’t imagine a situation in which a Basic programmer would be copying overlapped memory. No reason not to use MoveMemory instead. The name CopyMemory seemed more intelligible than hmemcpy or MoveMemory, so I used this alias for both 16-bit and 32-bit versions:

#If Win32 Then
Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" ( _
    lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
#Else
Declare Sub CopyMemory Lib "KERNEL" Alias "hmemcpy" ( _
    lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
#End If

The Windows API type library has an equivalent (or almost equivalent) CopyMemory function.

That explains why I used CopyMemory, but why does everybody else use it? Because I sent a copy of my sidebar to an internal alias at Microsoft, and someone who read it decided it would make a good Knowledge Base article. I agreed to let them use it if they mentioned it was an excerpt from my book. Good advertising, I thought. Ever since then I’ve read articles and heard speakers at the VBITS conference talking about CopyMemory as if it really existed. And none of them mention my book as the source. So don’t be fooled by false advertising. If they talk about RtlMoveMemory, they figured it out on their own. If they talk about CopyMemory, they got it (perhaps without knowing) from me.
.
.
.
0
 
LVL 32

Expert Comment

by:Erick37
ID: 13800864
The CopyMemory method works because a VB Single data type uses the IEEE-754 method.  So all we need to do is find a way to set the value of the bytes directly in our Single variable.

First thing to do is to convert the string representation of the Hex value in to memory.  Easily done with the Val() function and assigning the result to a Long data type (4 bytes).

Now that we have the 4 bytes in memory, use CopyMemory() to copy the same bytes into a variable declared as Single.

Another use of CopyMemory can be found here (with a better explanation than mine) :)

"How To Retrieve Individual Bytes from a Multi-Byte Type in VB"
http://support.microsoft.com/default.aspx?scid=kb;en-us;171652
0
 
LVL 4

Expert Comment

by:rdwillett
ID: 13801044
Try mine, it is currently used to convert PLC data 24 hours a day seven days a week.  It converts approximately 400 values every 60 ms and works fine.  Did not think about the CopyMemory issues.
0
 
LVL 1

Author Comment

by:mushu999
ID: 13801252
I was in a bind to get the fix out the door last night, so after spending much time testing Erick's tiny solution I implemented it in my app. However, I can see a potential need to have the split-apart numeric fields that rd's solution provides in the future. Thus I split the answer points...hope neither of you are offended!
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction While answering a recent question about filtering a custom class collection, I realized that this could be accomplished with very little code by using the ScriptControl (SC) library.  This article will introduce you to the SC library a…
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
Suggested Courses

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question