How can I simplify and optimize this checksumming code?
Ok this code works but I think it has some necessary steps in the middle to get to the outcome. Any thoughts on how to make it tighter?
Public Function CalCheckSum(ByVal By开发者_Python百科teList As List(Of Byte)) As List(Of Byte)
Dim total As Integer = 0
For Each b As Byte In ByteList
total = total + b
Next
Dim modedVal As Integer = 0
modedVal = total Mod &H100
Dim negatedValue As Integer = 0
negatedValue = &H100 - modedVal
Dim charList As List(Of Char) = Hex(negatedValue).ToCharArray.ToList
Dim returnList As New List(Of Byte)
For Each ch As Char In charList
returnList.Add(Asc(ch))
Next
Return returnList
End Function
BTW This is what I'm using to test it:
Dim blist As New List(Of Byte)
blist.Add(&H52)
blist.Add(&H34)
blist.Add(&H35)
blist.Add(&H31)
blist.Add(&H32)
blist.Add(&H33)
blist.Add(&H34)
blist.Add(&H30)
blist.Add(&H30)
blist.Add(&H30)
blist.Add(&H30)
blist.Add(&H46)
blist.Add(&H46)
blist.Add(&H46)
blist.Add(&H46)
blist.Add(&H42)
blist.Add(&H4B)
blist.Add(&H9)
blist.Add(&H44)
Dim b As List(Of Byte) = CalCheckSum(blist)
The correct values for b
are:
b(0)
= &H43b(1)
= &H39
I'm honestly not sure why you'd waste the time it takes to optimize this. Calling that function over 100,000 times in a loop takes less than 20 milliseconds. Even if this is one of the "hot points" in your application (since you say it communicates with an embedded hardware device), it's unlikely that you'll see any appreciable speed increase by optimizing the code that you have.
But just for fun, I decided to see if I couldn't optimize things a little anyway... Here's what I came up with:
Remove the redundant
List(Of Char)
creation. You're already converting the values to an array with theToCharArray
method. Why go through the expense of callingToList
on that, just to iterate through it? You can iterate just as well through an array. This shaves the time down to around 8 seconds, a pretty massive speed-up for minimal effort.You can also pass in the approximate size of your new
List(Of Byte)
as an argument to the constructor. You already know this from the size of yourcharArray
, since you're just adding each of those elements back in. This doesn't make any difference when you're only working with two items, as in the example you provided, but it could make things slightly more efficient for substantially larger numbers of elements because theList
wouldn't have to be dynamically resized at any point during the loop.There's absolutely no difference between
Asc
,AscW
, andConvert.ToInt32
. I measured each of them explicitly just to see. My gut instinct was to change that toAscW
, but apparently it doesn't matter. Lots of people will turn their nose up at the use of VB-specific idioms, and recommend what they consider more universal methods provided by the .NET Framework. It turns out that since all the VB-specific code is written in the same managed code as the alternatives, it's a simple matter of preference which you use.Otherwise replacing
List(Of T)
with simple arrays doesn't make any appreciable difference, either. Since aList
is easier to work with outside of the function, you might as well keep it as the returned type.
So my final code looks something like this:
Public Function CalCheckSum(ByVal ByteList As List(Of Byte)) As List(Of Byte)
Dim total As Integer = 0
For Each b As Byte In ByteList
total = total + b
Next
Dim negatedValue As Integer = 0
negatedValue = &H100 - (total Mod &H100)
Dim charArray As Char() = Hex(negatedValue).ToCharArray()
Dim returnList As New List(Of Byte)(charArray.Length)
For Each ch As Char In charArray
returnList.Add(CByte(Asc(ch)))
Next
Return returnList
End Function
Even running this 999,000 times in a loop, I consistently clock it somewhere between 62 and 64 ms.
You could also use LINQ. It's not really my area, and I doubt you'll see any measurable speed increases (it still has to do the same amount of looping and iterating under the covers). The big benefit it provides is that your code is simpler and looks cleaner. I'm surprised someone hasn't already posted this solution.
EDIT: As an aside, your original code didn't compile for me. I had to add in the CByte
operator to convert the Integer
value returned from the Asc
operator into a Byte
type. That tells me that you're not programming with Option Strict On. But you should be. You have to explicitly set the option in your project's properties, but the benefits of strong typing far outweigh the cost of going through and fixing some of your existing code. You might even notice a performance increase, especially if you've been using a lot of late binding inadvertently.
精彩评论