Results 1 to 10 of 10

Thread: [RESOLVED] Splitting a Long into two Integers

  1. #1

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Resolved [RESOLVED] Splitting a Long into two Integers

    There is a scheme already in place to combine two integer coordinates into one Long value. The integers range from -400 to 400, on both an x and y axis.

    I do not know the logic driving how the coordinates are combined into one value. I assume it is a simple "high byte low byte" technique using a high integer and low integer. But I don't know how to do that.

    Here are some actual values:

    200,200 = 160801
    -100,-100 = 400801
    255,0 = 321056
    0,255 = 116546
    -127,127 = 218947
    63,-63 = 371327

    How do I go from coordinates to long and back again?

  2. #2

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Splitting a Long into two Integers

    Hmmm. I found this:
    Code:
    Public Function GetLoWord(l As Long) As Integer
        GetLoWord = (l / &H10000) And &HFFFF&
    End Function
    
    Public Function GetHiWord(l As Long) As Integer
        GetHiWord = l And &HFFFF&
    End Function
    
    Public Function IntegersToLong(LoWord As Integer, _
       HiWord As Integer) As Long
    
    IntegersToLong = (HiWord * &H10000) + (LoWord And &HFFFF&)
    
    End Function
    Unfortunately, it isn't combining them the same way, so it's no help to me. This means it won't be as simple as I originally hoped (assumed) it would be.

    It is worth pointing out that the resulting long is never negative in the scheme I'm trying to figure out.
    Last edited by Ellis Dee; Oct 11th, 2008 at 09:56 AM.

  3. #3

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Splitting a Long into two Integers

    For testing purposes, I can post the resulting long of any coordinate pair you like, so feel free to ask. I just can't figure out how they're being generated.

  4. #4

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Splitting a Long into two Integers

    Here are the limit values:

    -400,400 = 1
    400,400 = 801
    0,0 = 320801
    -400,-400 = 640801
    400,-400 = 641601

  5. #5

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Splitting a Long into two Integers

    Hmmm. -400 to 400 includes 0, meaning there are 801 possible values along each axis. 801 * 801 = 641601, which is the limit based on the previous post.

    Looks like it's using the technique you'd use to hold multi-dimensional data in a single-dimension array.

  6. #6

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: Splitting a Long into two Integers

    We have a winner:
    Code:
    Public Function XYtoZ(pintX As Integer, pintY As Integer) As Long
        XYtoZ = (400 - pintY) * 801& + pintX + 401
    End Function

  7. #7
    PowerPoster
    Join Date
    May 2006
    Location
    Location, location!
    Posts
    2,673

    Re: [RESOLVED] Splitting a Long into two Integers

    I hope you rated your own post after finding your own result :-P
    Well, everyone else has been doing it :-)
    Loading a file into memory QUICKLY - Using SendKeys - HyperLabel - A highly customisable label replacement - Using resource files/DLLs with VB - Adding GZip to your projects
    Expect more to come in future
    If I have helped you, RATE ME! :-)

    I love helping noobs with their VB problems (probably because, as an amateur programmer, I am only slightly better at VB than them :-)) but if you SERIOUSLY want to get help for free from a community such as VBForums, you have to first have a grounding (basic knowledge) in VB6, otherwise you're way too much work to help...You've got to give a little if you want to get help from us, in other words!

    And we DON'T do your homework. If your tutor doesn't teach you enough to help you make the project without his or her help, FIND A BETTER TUTOR or try reading books on programming! We are happy to help with minor things regarding the project, but you have to understand the rest of it if you want our help to be useful.

  8. #8
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: [RESOLVED] Splitting a Long into two Integers

    Just to share the information, here is a different method for getting and setting high and low Integers in Longs:
    Code:
    Option Explicit
    
    Private Type Integer32
        Low As Integer
        High As Integer
    End Type
    
    Private Type Long32
        Value As Long
    End Type
    
    Public Function IntegerToLong(ByVal Low As Integer, ByVal High As Integer) As Long
        Dim intValue As Integer32, lngValue As Long32
        intValue.Low = Low
        intValue.High = High
        LSet lngValue = intValue
        IntegerToLong = lngValue.Value
    End Function
    
    Public Sub LongToInteger(ByVal Value As Long, ByRef Low As Integer, ByRef High As Integer)
        Dim intValue As Integer32, lngValue As Long32
        lngValue.Value = Value
        LSet intValue = lngValue
        Low = intValue.Low
        High = intValue.High
    End Sub
    Since it only involves copying bits instead of using math it should be faster (although I have never timed this and I don't really even care to - it is just a very useful technique to know at times).


    Edit!
    Here a highly validating functions for your problem:
    Code:
    Public Function XYtoZ(ByVal X As Integer, ByVal Y As Integer) As Long
        If X >= -400 And X <= 400 And Y >= -400 And Y <= 400 Then
            XYtoZ = CLng(400 - Y) * 801 + X + 401
        End If
    End Function
    
    Public Function ZtoX(ByVal Value As Long) As Integer
        If Value >= 1 And Value <= 641601 Then
            ZtoX = ((Value - 1) Mod 801) - 400
        End If
    End Function
    
    Public Function ZtoY(ByVal Value As Long) As Integer
        If Value >= 1 And Value <= 641601 Then
            ZtoY = -((Value - 1) \ 801) + 400
        End If
    End Function
    
    Public Function ZtoXY(ByVal Value As Long, X As Integer, Y As Integer) As Boolean
        ZtoXY = Value >= 1 And Value <= 641601
        If ZtoXY Then
            X = ((Value - 1) Mod 801) - 400
            Y = -((Value - 1) \ 801) + 400
        End If
    End Function
    And a horrible test code:
    Code:
        Debug.Print ZtoX(XYtoZ(-400, 400)), ZtoY(XYtoZ(-400, 400))
        Debug.Print ZtoX(XYtoZ(400, 400)), ZtoY(XYtoZ(400, 400))
        Debug.Print ZtoX(XYtoZ(0, 0)), ZtoY(XYtoZ(0, 0))
        Debug.Print ZtoX(XYtoZ(-400, -400)), ZtoY(XYtoZ(-400, -400))
        Debug.Print ZtoX(XYtoZ(400, -400)), ZtoY(XYtoZ(400, -400))
    Last edited by Merri; Oct 11th, 2008 at 11:44 AM.

  9. #9

    Thread Starter
    PowerPoster Ellis Dee's Avatar
    Join Date
    Mar 2007
    Location
    New England
    Posts
    3,530

    Re: [RESOLVED] Splitting a Long into two Integers

    Nice!

  10. #10
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: [RESOLVED] Splitting a Long into two Integers

    Darn, I did bother to do a Type vs. Math benchmark. Silly me.

    Results IDE
    Type version: 3.71 seconds
    Math version: 3.16 seconds

    Results compiled (all advanced optimizations on)
    Type version: 0.728 seconds
    Math version: 0.216 seconds


    Tested functions:
    Code:
    Option Explicit
    
    Private Type Integer32
        Low As Integer
        High As Integer
    End Type
    
    Private Type Long32
        Value As Long
    End Type
    
    Public Function IntegerToLong(ByVal Low As Integer, ByVal High As Integer) As Long
        Dim intValue As Integer32, lngValue As Long32
        intValue.Low = Low: intValue.High = High
        LSet lngValue = intValue
        IntegerToLong = lngValue.Value
    End Function
    
    Public Function IntegerToLong2(ByVal Low As Integer, ByVal High As Integer) As Long
        IntegerToLong2 = ((High And &H7FFF&) * &H10000) Or (Low And &HFFFF&) Or (&H80000000 And High < 0)
    End Function
    
    Public Sub LongToInteger(ByVal Value As Long, ByRef Low As Integer, ByRef High As Integer)
        Dim intValue As Integer32, lngValue As Long32
        lngValue.Value = Value
        LSet intValue = lngValue
        Low = intValue.Low: High = intValue.High
    End Sub
    
    Public Sub LongToInteger2(ByVal Value As Long, ByRef Low As Integer, ByRef High As Integer)
        Low = (Value And &H7FFF) Or (&H8000 And (Value And &H8000) <> 0)
        High = ((Value And &H7FFF0000) \ &H10000) Or (&H8000 And Value < 0)
    End Sub
    Note: the math ones are complex simply to support negative values.

    Test project:
    Code:
    Option Explicit
    
    Const ITERATIONS = 10000000
    Const TEST = &H80008000
    
    Private Declare Function QueryPerformanceCounter Lib "kernel32" (X As Currency) As Boolean
    Private Declare Function QueryPerformanceFrequency Lib "kernel32" (X As Currency) As Boolean
    
    Dim m_Time As Double
    Dim m_TimeFreq As Double
    Dim m_TimeStart As Currency
    
    Public Property Get Timing() As Double
        Dim curTime As Currency
        QueryPerformanceCounter curTime
        Timing = (curTime - m_TimeStart) * m_TimeFreq + m_Time
    End Property
    
    Public Property Let Timing(ByVal NewValue As Double)
        Dim curFreq As Currency, curOverhead As Currency
        m_Time = NewValue
        If m_TimeFreq Then
        Else
            QueryPerformanceFrequency curFreq
            m_TimeFreq = 1 / curFreq
        End If
        QueryPerformanceCounter curOverhead
        QueryPerformanceCounter m_TimeStart
        m_TimeStart = m_TimeStart + (m_TimeStart - curOverhead)
    End Property
    
    Private Sub Command1_Click()
        Dim int1 As Integer, int2 As Integer, lng1 As Long
        Dim lngA As Long
        Timing = 0
        For lngA = 1 To ITERATIONS
            LongToInteger TEST, int1, int2
            lng1 = IntegerToLong(int1, int2)
        Next lngA
        Command1.Caption = "Type version: " & Format$(Timing, "0.00000") & " sec: " & (lng1 = TEST)
    End Sub
    
    Private Sub Command2_Click()
        Dim int1 As Integer, int2 As Integer, lng1 As Long
        Dim lngA As Long
        Timing = 0
        For lngA = 1 To ITERATIONS
            LongToInteger2 TEST, int1, int2
            lng1 = IntegerToLong2(int1, int2)
        Next lngA
        Command2.Caption = "Math version: " & Format$(Timing, "0.00000") & " sec: " & (lng1 = TEST)
    End Sub
    Thus math is the way to go in this case. You can't use it as easily in other cases though, such as when placing a 64-bit value to Currency from two Longs.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width