Solved

Request for binary <-> Long info (2's complement?)

Posted on 2003-12-08
8
366 Views
Last Modified: 2010-05-03
I've been trying to find a decimal to binary and binary to decimal function that works correctly with negative numbers, but so far, none have held up to the challenge.  I want this to work in Visual Basic, but the VB code will eventually be ported to ASP, so I would rather avoid using external components.

For example, I am reading a Long value from a file.  This value is negative, eg, -1487631.  When I attempt to convert this to binary using the following function, I of course get a 0 since the function only does positive numbers.

If I try to read the Long as 4 bytes, then convert each byte into an 8 bit binary string, and concatate the 4 strings together, then try to convert the binary string back to a long, I get a number like 1487630.

My question is, how exactly are 4 byte negative longs (or 2 byte negative integers, etc) stored in either files or memory?  What's the best way to correctly convert from a negative or positive number of an arbitrary byte length (anything from 1 byte to 32 bytes, even odd ones such as 5, 17, etc)?

Here are the functions I'm currently using.

Public Function Dec2Bin(ByVal Num As Variant) As String
Dim x As Integer

For x = 100 To 0 Step -1 ' I don't expect to ever use a number bigger than (2 ^ 100)

If Num >= (2 ^ x) Then
'    Stop
    Dec2Bin = Dec2Bin & "1"
    Num = Num - (2 ^ x)
Else
    Dec2Bin = Dec2Bin & "0"
End If

Next x

Do While Left(Dec2Bin, 1) = "0"
    Dec2Bin = Mid(Dec2Bin, 2) ' Remove all extra 0's from the front.
Loop

Do Until Len(Dec2Bin) Mod 8 = 0 And Len(Dec2Bin) <> 0 ' Make sure there are 8 'bits' returned
    Dec2Bin = "0" & Dec2Bin
Loop

End Function

Public Function Bin2Dec(ByVal Bin As String) As Variant
Dim x As Integer

For x = 1 To Len(Bin)
    Bin2Dec = Bin2Dec + Int(Mid(StrReverse(Bin), x, 1) * (2 ^ (x - 1)))
Next x

End Function

Current points set at 250, but I'm willing to increase it for a prompt response, or information that goes above and beyond what I've asked for.

James
0
Comment
Question by:Lycaon
  • 4
  • 4
8 Comments
 
LVL 7

Expert Comment

by:Z_Beeblebrox
ID: 9898673
Here is a very simple (and kind of cheap) answer. Just use VB to do the conversion.

Public Function Bin2Dec(Bin as string) as Long

Dim x as integer

for x = 1 to len(bin)
   Bin2Dec = Bin2Dec OR Int(Mid(StrReverse(Bin), x, 1) * (2 ^ (x - 1)))
next

End Function

Public Function Dec2Bin(Dec as Long) as String

Dim x as integer

for x = 1 to 32
   Dec2Bin = iif(mid(dec,x,1) = "1",1,0)*(2^(32-x))
next

End Function

That's all freehand, so there might be some glitches, but hopefully you get the idea.

Zaphod.
0
 
LVL 7

Expert Comment

by:Z_Beeblebrox
ID: 9898763
Okay, everything I told you is incorrect. It's not quite as simple as I made it out to be. Darn me and my attempts to do unsigned operations in VB....

Zaphod.
0
 
LVL 1

Author Comment

by:Lycaon
ID: 9899028
Heh *grin*.

How so?
0
 
LVL 1

Author Comment

by:Lycaon
ID: 9900151
*dangles another 250 points in front of everyone*
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 7

Expert Comment

by:Z_Beeblebrox
ID: 9901100
Hi,

Fewf, that turned out to be a lot harder than I thought it would be. Be aware that this uses the internal representation of longs to do its work, which is done in little endian, so some of the loops might seem backwards, but they aren't really. This will work with bytes, integers and longs normally for Bin2Dec, and will also work for Dec2Bin, but it will always return a 32 bit value, you can just truncate the first 2 or 3 bytes for integers and bytes respectively since they will all be either 1 or 0 anyway and are not needed.

Hope this does the trick.
Zaphod.

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

Private Function Dec2Bin(ByVal Value As Long) As String

    Dim strRetVal As String
    Dim arrBytes(0 To 3) As Byte
    Dim i As Integer
    Dim j As Integer
   
    CopyMemory arrBytes(0), Value, 4
    For i = 3 To 0 Step -1
        For j = 7 To 0 Step -1
            strRetVal = strRetVal & (arrBytes(i) And (2 ^ j)) / (2 ^ j)
        Next
    Next
   
    Dec2Bin = strRetVal
   
End Function

Private Function Bin2Dec(ByVal Value As String) As Long

    Dim lngRetVal As Long
    Dim arrBytes(0 To 3) As Byte
    Dim strSign As String
    Dim i As Integer
    Dim j As Integer
    Dim k As Integer
   
    ' Pad the string with the sign bit
    Value = String(32 - Len(Value), Left(Value, 1)) & Value
   
    k = 1
    For i = 3 To 0 Step -1
        For j = 7 To 0 Step -1
            If Mid(Value, k, 1) = "1" Then
                arrBytes(i) = arrBytes(i) Or (2 ^ (j))
            End If
            k = k + 1
        Next
    Next
     
    CopyMemory lngRetVal, arrBytes(0), 4
   
    Bin2Dec = lngRetVal
End Function
0
 
LVL 1

Author Comment

by:Lycaon
ID: 9901985
Dude, that's magic.  (Sorry, just watched Austin Powers: Goldmember, heh)

One question though.  Is there any way around the CopyMemory call?  As it mentions in the first or second paragraph I hope to port this to ASP, and you can't do API in ASP :\

James
0
 
LVL 7

Accepted Solution

by:
Z_Beeblebrox earned 500 total points
ID: 9931840
I like a good challenge. Sorry it took me so long to tackling it. Here ya go!

Zaphod.

Private Function Dec2Bin(ByVal Value As Long) As String

    Dim blnIsNegative As Boolean
    Dim intPower As Integer
    Dim strRetVal As String
   
    blnIsNegative = (Value < 0)
    Value = Abs(Value)
   
    While Value > 0
        strRetVal = CStr(Value Mod 2) & strRetVal
        Value = Value \ 2
    Wend
   
    strRetVal = String(32 - Len(strRetVal), "0") & strRetVal
   
    If blnIsNegative Then
        strRetVal = TwosComplement(strRetVal)
    End If
   
    Dec2Bin = strRetVal

End Function

Private Function Bin2Dec(ByVal Value As String) As Long

    Dim blnIsNegative As Boolean
    Dim intPower As Integer
    Dim lngRetVal As Long
   
    blnIsNegative = (Left(Value, 1) = "1")
   
    If blnIsNegative Then
        Value = TwosComplement(Value)
    End If
     
    For intPower = 0 To Len(Value) - 1
        If Mid(Value, Len(Value) - intPower, 1) = "1" Then
            lngRetVal = lngRetVal + (2 ^ intPower)
        End If
    Next
     
    If blnIsNegative Then
        lngRetVal = -lngRetVal
    End If
   
    Bin2Dec = lngRetVal
   
End Function

Private Function TwosComplement(ByVal Value As String) As String

    Dim intPos As Integer

    Value = Replace(Value, "0", "x")
    Value = Replace(Value, "1", "0")
    Value = Replace(Value, "x", "1")
    intPos = InStrRev(Value, "0")
    Value = Left(Value, intPos - 1) & "1" & String(32 - intPos, "0")
   
    TwosComplement = Value
   
End Function
0
 
LVL 1

Author Comment

by:Lycaon
ID: 9986293
Excellent.  Here you go.  Thanks :)

James
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This article describes some techniques which will make your VBA or Visual Basic Classic code easier to understand and maintain, whether by you, your replacement, or another Experts-Exchange expert.
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
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…

743 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now