|
-
Oct 11th, 2008, 09:47 AM
#1
[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?
-
Oct 11th, 2008, 09:53 AM
#2
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.
-
Oct 11th, 2008, 09:55 AM
#3
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.
-
Oct 11th, 2008, 10:01 AM
#4
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
-
Oct 11th, 2008, 10:05 AM
#5
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.
-
Oct 11th, 2008, 10:20 AM
#6
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
-
Oct 11th, 2008, 10:52 AM
#7
PowerPoster
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.
-
Oct 11th, 2008, 11:24 AM
#8
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.
-
Oct 11th, 2008, 07:38 PM
#9
Re: [RESOLVED] Splitting a Long into two Integers
-
Oct 12th, 2008, 03:46 AM
#10
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|