Re: Byte swapping efficiently
- From: "Mike D Sutton" <EDais@xxxxxxxx>
- Date: Wed, 3 May 2006 01:17:45 +0100
Anyone good at low-level data manipulation?
I'm working on an app that reads 16-bit signed integers in Motorola
(MSB-first) format, and needs to swap the two bytes into Intel
(LSB-first) order and return them as a Single. Currently, it uses the
following function to do the job, and it seems to work okay:
Public Function ByteSwap(Value As Integer) As Single
Dim S As String
Dim Result As String
Dim I As Single
S = Hex$(Value)
S = String(4 - Len(S), "0") & S
For I = 3 To 1 Step -2
Result = Result & Mid(S, I, 2)
Next
ByteSwap = Val("&H" & Result)
End Function
Unfortunately, that gets called a helluva lot, and debugging indicates
that the function is a major bottleneck. Not surprising, with all
that string handling going on.
Two things strike me: (a) there must be a much more efficient way to
do the job, maybe in a single line of code, and (b) I haven't a clue
what it is.
Here's the various functions I've profiled:
'***
Private Declare Sub RtlMoveMemory Lib "Kernel32.dll" ( _
ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub PutByte Lib "MSVBVM60.dll" Alias "PutMem1" ( _
ByRef inDst As Any, ByVal inSrc As Byte)
Private Declare Sub GetByte Lib "MSVBVM60.dll" Alias "GetMem1" ( _
ByRef inSrc As Any, ByRef inDst As Byte)
Private Declare Sub GetWord Lib "MSVBVM60.dll" Alias "GetMem2" ( _
ByRef inSrc As Any, ByRef inDst As Integer)
Public Function FlipWordA(ByVal Value As Integer) As Integer
Dim S As String
Dim Result As String
Dim I As Single
S = Hex$(Value)
S = String(4 - Len(S), "0") & S
For I = 3 To 1 Step -2
Result = Result & Mid(S, I, 2)
Next
FlipWordA = Val("&H" & Result)
End Function
Private Function FlipWordB(ByVal inWord As Integer) As Integer ' Endian swap
on Word
FlipWordB = ((inWord And &H7F) * &H100) Or (((inWord And &HFF00) \
&H100) And &HFF)
If (inWord And &H80) Then FlipWordB = FlipWordB Or &H8000
End Function
Private Function FlipWordC(ByVal inWord As Integer) As Integer
Call RtlMoveMemory(ByVal VarPtr(FlipWordC), ByVal (VarPtr(inWord) + 1),
1&)
Call RtlMoveMemory(ByVal (VarPtr(FlipWordC) + 1), ByVal VarPtr(inWord),
1&)
End Function
Private Function FlipWordD(ByVal inWord As Integer) As Integer
Dim TempByte As Byte
Call GetByte(ByVal VarPtr(inWord), TempByte)
Call PutByte(ByVal (VarPtr(FlipWordD) + 1), TempByte)
Call GetByte(ByVal (VarPtr(inWord) + 1), TempByte)
Call PutByte(ByVal VarPtr(FlipWordD), TempByte)
End Function
Private Function FlipWordE(ByVal inWord As Integer) As Integer
Call GetWord(ByVal VarPtr(((CLng(inWord) And &HFF&) * &H100&) Or _
((inWord And &HFF00&) \ &H100&)), FlipWordE)
End Function
Private Function FlipWordF(ByVal inWord As Integer) As Integer
Dim S As String
S = Right$("0000" & Hex$(inWord), 4)
FlipWordF = Val("&H" & Mid$(S & S, 3, 4))
End Function
Private Function FlipWordG(ByVal inWord As Integer) As Integer
Dim ByteHi As Integer
Dim ByteLo As Integer
Dim NewHi As Long
' Separate bytes using same strategy as in
' ByteHi and ByteLo functions. Faster to do
' it inline than to make function calls.
If (inWord < 0) Then
ByteHi = (inWord + &H10000) \ &H100
Else
ByteHi = inWord \ &H100
End If
ByteLo = inWord And &HFF
' Shift low byte left by 8
NewHi = ByteLo * &H100&
' Account for sign-bit
If (NewHi > &H7FFF) Then
ByteLo = NewHi - &H10000
Else
ByteLo = NewHi
End If
' Place high byte in low position
FlipWordG = ByteLo Or ByteHi
End Function
'***
Here's the performance results for one million iterations:
Machine A (Dual 2.4Ghz P4, 1GB RDRAM, WinXP Pro)
IDE:
FlipWordA: 3847.710
FlipWordB: 588.520
FlipWordC: 709.825
FlipWordD: 745.134
FlipWordE: 509.211
FlipWordF: 2395.273
FlipWordG: 708.668
EXE:
FlipWordA: 2793.625
FlipWordB: 15.582
FlipWordC: 172.171
FlipWordD: 121.774
FlipWordE: 39.321
FlipWordF: 1726.534
FlipWordG: 28.215
EXE with advanced compile options checked:
FlipWordA: 2730.523
FlipWordB: 10.112
FlipWordC: 171.097
FlipWordD: 121.235
FlipWordE: 38.871
FlipWordF: 1693.779
FlipWordG: 10.806
Machine B (P4 1.4 Laptop, 1GB RAM, WinXP Pro)
IDE:
FlipWordA: 5553.397
FlipWordB: 722.870
FlipWordC: 953.164
FlipWordD: 939.081
FlipWordE: 690.923
FlipWordF: 3527.865
FlipWordG: 951.152
EXE:
FlipWordA: 4017.691
FlipWordB: 18.363
FlipWordC: 268.563
FlipWordD: 154.108
FlipWordE: 49.172
FlipWordF: 2526.460
FlipWordG: 32.973
EXE with advanced compile options checked:
FlipWordA: 4031.840
FlipWordB: 13.435
FlipWordC: 265.573
FlipWordD: 156.228
FlipWordE: 77.674
FlipWordF: 2560.907
FlipWordG: 12.842
Looks like FlipWordE() in the IDE, and FlipWordB() or FlipWordG() compiled
are the ones to go for if performance is your goal.
Hope this helps,
Mike
P.s. Hey Rick, check out FlipWordE() - It's a one liner for you!
- Microsoft Visual Basic MVP -
E-Mail: EDais@xxxxxxxx
WWW: Http://EDais.mvps.org/
.
- Follow-Ups:
- Re: Byte swapping efficiently
- From: John Hatpin
- Re: Byte swapping efficiently
- From: Tony Proctor
- Re: Byte swapping efficiently
- From: Rick Rothstein
- Re: Byte swapping efficiently
- References:
- Byte swapping efficiently
- From: John Hatpin
- Byte swapping efficiently
- Prev by Date: Re: Using with
- Next by Date: Re: Byte swapping efficiently
- Previous by thread: Re: Byte swapping efficiently
- Next by thread: Re: Byte swapping efficiently
- Index(es):