algorithm - 这个 SuperFashHash 实现是否计算字符串的正确 31 位散列?

标签 algorithm vba hash excel

我正在 VBA 中实现 SuperFastHash 的一个变体,以便在 Excel(32 位版本,因此没有可用的 LongLong)中使用来哈希字符串。

为了解决带符号的 32 位 Long 值的限制,我使用 Double 类型进行加法和位移,然后以将其截断为 31 位(最大正数)的方式从 Double 转换为 Long值 -- 不想处理补码和符号)。

到目前为止我得到了答案并避免了溢出,但我怀疑我在翻译中犯了一些错误,因为大多数实现使用 uint 的所有 32 位并且还处理数组中的单个字节而不是 16 - 来自 AscW() 的位值。

实现的具体部分我希望有人可以直觉检查:

  1. 我如何测试 16 位字符单词而不是 4 字节 block 。
  2. 考虑到我需要将 Long 值截断为 31 位的警告,我的位移位操作在技术上是否正确。
  3. 考虑到哈希仅使用 31 位,最后的雪崩片是否仍然合适。

这是当前代码:

Public Function shr(ByVal Value As Long, ByVal Shift As Byte) As Long
    shr = Value
    If Shift > 0 Then shr = shr \ (2 ^ Shift)
End Function

Public Function shl(ByVal Value As Long, ByVal Shift As Byte) As Long
    If Shift > 0 Then
        shl = LimitDouble(CDbl(Value) * (2& ^ Shift))
    Else
        shl = Value
    End If
End Function

Public Function LimitDouble(ByVal d As Double) As Long
    '' Prevent overflow by lopping off anything beyond 31 bits
    Const MaxNumber As Double = 2 ^ 31
    LimitDouble = CLng(d - (Fix(d / MaxNumber) * MaxNumber))
End Function

Public Function SuperFastHash(ByVal dataToHash As String) As Long
    Dim dataLength As Long
    dataLength = Len(dataToHash)
    If (dataLength = 0) Then
        SuperFastHash = 0
        Exit Function
    End If
    Dim hash As Long
    hash = dataLength
    Dim remainingBytes As Integer
    remainingBytes = dataLength Mod 2
    Dim numberOfLoops As Integer
    numberOfLoops = dataLength \ 2
    Dim currentIndex As Integer
    currentIndex = 0
    Dim tmp As Double
    Do While (numberOfLoops > 0)
        hash = LimitDouble(CDbl(hash) + AscW(Mid$(dataToHash, currentIndex + 1, 1)))
        tmp = shl(AscW(Mid$(dataToHash, currentIndex + 2, 1)), 11) Xor hash
        hash = shl(hash, 16) Xor tmp
        hash = LimitDouble(CDbl(hash) + shr(hash, 11))
        currentIndex = currentIndex + 2
        numberOfLoops = numberOfLoops - 1
    Loop
    If remainingBytes = 1 Then
        hash = LimitDouble(CDbl(hash) + AscW(Mid$(dataToHash, currentIndex + 1, 1)))
        hash = hash Xor shl(hash, 10)
        hash = LimitDouble(CDbl(hash) + shr(hash, 1))
    End If
    '' Final avalanche
    hash = hash Xor shl(hash, 3)
    hash = LimitDouble(CDbl(hash) + shr(hash, 5))
    hash = hash Xor shl(hash, 4)
    hash = LimitDouble(CDbl(hash) + shr(hash, 17))
    hash = hash Xor shl(hash, 25)
    hash = LimitDouble(CDbl(hash) + shr(hash, 6))
    SuperFastHash = hash
End Function

最佳答案

我建议您最好将 32 位字分成两个“16 位”部分,每个部分都保存在一个带符号的 32 位变量中(使用每个变量的低 16 位,然后“规范化”步骤之间的值:

highPart = (highPart + (lowPart \ 65536)) and 65535
lowPart = lowPart and 65535

左移16位简单的说就是把低位复制到高位,低位归零。右移 16 位只是将高位部分复制到低位部分并将高位部分归零。向左移动较少的位置只是意味着分别移动两个部分然后归一化。将归一化数字右移较少的位置意味着将两个部分都左移 (16-N) 位,归一化,然后右移 16 位。

关于algorithm - 这个 SuperFashHash 实现是否计算字符串的正确 31 位散列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12806761/

相关文章:

algorithm - d3 v4 中的 tree.nodeSize

vba - 列中的五个最大值

vba - 在Excel VBA中,如何删除灰色分页符?

javascript - 使用 Javascript 解析 Ruby 哈希文本

boost MD5 支持?

algorithm - 合并散列删除算法

python - 如何使用 Python 从链表中删除给定节点

用于按多个条件对对象中的数组进行排序的 JavaScript 算法

algorithm - 什么是监督 ML 分类算法?

excel - 从 Outlook VBA 激活工作表