如何简化和优化此校验和代码?

发布于 2024-10-14 15:31:27 字数 1284 浏览 4 评论 0原文

好的,这段代码可以工作,但我认为中间有一些必要的步骤才能达到结果。关于如何使其更紧有什么想法吗?

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 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

顺便说一句,这就是我用来测试它的内容:

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)

b 的正确值是:

  • b(0) = &H43
  • b(1) = &H39

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 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 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) = &H43
  • b(1) = &H39

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烟雨凡馨 2024-10-21 15:31:27

老实说,我不确定您为什么要浪费时间来优化它。在循环中调用该函数超过 100,000 次需要不到 20 毫秒。即使这是应用程序中的“热点”之一(因为您说它与嵌入式硬件设备通信),您也不太可能通过优化现有代码看到任何明显的速度提升。

但只是为了好玩,我决定看看我是否不能稍微优化一下...这是我想到的:

  1. 删除多余的 List(Of Char) 创建。您已经使用 ToCharArray 方法将值转换为数组。为什么要花大力气调用 ToList 来遍历它呢?您也可以迭代数组。这将时间缩短至大约 8 秒,以最小的努力实现了相当大的加速。

  2. 您还可以将新List(Of Byte)的大致大小作为参数传递给构造函数。您已经从 charArray 的大小中知道了这一点,因为您只是将每个元素添加回去。当您只处理两个项目时,这没有任何区别,如您提供的示例,但对于大量元素来说,它可以稍微提高效率,因为 List 不必在循环期间的任何时候动态调整大小。

  3. AscAscWConvert.ToInt32 之间完全没有区别。我明确地测量了它们中的每一个,只是为了看看。我的直觉是将其更改为 AscW,但显然这并不重要。许多人会对 VB 特定惯用语的使用嗤之以鼻,并推荐他们认为 .NET Framework 提供的更通用的方法。事实证明,由于所有特定于 VB 的代码都是用与替代代码相同的托管代码编写的,因此您使用的只是一个简单的偏好问题。

  4. 否则,用简单数组替换 List(Of T) 也不会产生任何明显的差异。由于 List 更容易在函数外部使用,因此您不妨将其保留为返回类型。

所以我的最终代码看起来像这样:

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

即使在循环中运行 999,000 次,我仍然将其计时在 62 到 64 毫秒之间。

您还可以使用LINQ。这不是我真正的领域,我怀疑您是否会看到任何可测量的速度增加(它仍然需要在幕后进行相同数量的循环和迭代)。它提供的最大好处是您的代码更简单并且看起来更干净。我很惊讶有人还没有发布这个解决方案。

编辑:顺便说一句,你的原始代码没有为我编译。我必须添加 CByte 运算符来将从 Asc 运算符返回的 Integer 值转换为 Byte 类型。这告诉我您没有使用 Option Strict 进行编程开。 但您应该这样做。您必须在项目属性中显式设置该选项,但强类型的好处远远超过了检查和修复某些现有代码的成本。您甚至可能会注意到性能有所提高,特别是如果您无意中使用了大量后期绑定。

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:

  1. Remove the redundant List(Of Char) creation. You're already converting the values to an array with the ToCharArray method. Why go through the expense of calling ToList 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.

  2. 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 your charArray, 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 the List wouldn't have to be dynamically resized at any point during the loop.

  3. There's absolutely no difference between Asc, AscW, and Convert.ToInt32. I measured each of them explicitly just to see. My gut instinct was to change that to AscW, 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.

  4. Otherwise replacing List(Of T) with simple arrays doesn't make any appreciable difference, either. Since a List 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文