【问题标题】:Fast calculate hamming distance in C在C中快速计算汉明距离
【发布时间】:2014-09-25 18:20:01
【问题描述】:

我阅读了Hamming Weight 上的维基百科文章并注意到一些有趣的事情:

因此等价于相同长度的全零字符串中的Hamming distance。对于最典型的情况,一串位,这是字符串中 1 的数量。在这种二进制情况下,它也称为人口计数,popcount 或横向总和。

[强调我的]

所以我想到了一些事情。我可以通过 XORing 计算两个字符串之间的汉明距离,然后获取结果字符串的汉明权重 (POPCOUNT) 吗?

类似的东西(使用gcc内在函数):

#include <stdint.h>

int hammingDistance (uint64_t x, uint64_t y) {
        uint64_t res = x ^ y;
        return __builtin_popcountll (res);
}

现在,至于我为什么要这样做,好吧,在某些平台上,是的,这只会转化为gcc 发出对计算popcount 的函数的调用。例如,在没有popcnt 的 x64 上,gcc 吐出 (Godbolt's GCC Online):

hammingDistance:
    sub rsp, 8
    xor rdi, rsi
    call    __popcountdi2
    add rsp, 8
    ret

OTOH,如果您有一个支持 POPCOUNT 的平台,例如 x64 模型,包括 nehalem 及之后的模型(有 POPCNT),您会得到 (Godbolt's GCC Online):

hammingDistance:
    xor rdi, rsi
    popcnt  rax, rdi
    ret

这应该更快,尤其是内联后。


但回到最初的问题。你能用两个字符串的异或的汉明权重来找到它们的汉明距离吗?即:

HD = HW (x xor y)

【问题讨论】:

  • 你是在问两个位串的异或的汉明权重是否等于它们的汉明距离? (答案:是的,从定义中可以轻松得出结论。)或者您是否要求将这种有效方法推广到一般字符串?
  • 我问的是第一个以及我的实现是否也有效。
  • 有趣的是,popcnt 并不总是最快的解决方案。在 Intel Haswell 处理器上,AVX2 寄存器内查找表方法更快。这里有一个可以测试各种人口计数方法的实用程序:notabs.org/blcutil

标签: c gcc intrinsics hamming-distance


【解决方案1】:

两个相等长度的字符串xy 之间的汉明距离定义为它们不同的位置数。在xy 是位串的情况下,x^y 是一个字符串,1s 的位置正好不同。因此,HammingDistance(x,y) = Number of 1s in x^y 用于位串。此外,HammingWeight(x) = number of 1s in x 用于位串 x。因此,您的第一个声明 HammingDistance(x,y) = HammingWeight(x^y) 对于位串是正确的。确定这一点后,很明显您的实现是正确的。

【讨论】:

  • 两个答案都一样好;话虽如此,我将其标记为正确,因为它是第一个。
【解决方案2】:

是的,这行得通。对于每个位,当且仅当输入位不同时,该位才为 1。因此,应用于整个位向量,结果具有与输入具有不同位 (HD) 一样多的一位 (HW)。而且您的代码似乎很好地利用了这种关系。事实上,这个捷径甚至在你链接到的汉明权重文章中进一步提到(Efficient implementation):

两个词A和B的汉明距离可以计算为A xor B的汉明权重。

【讨论】:

  • 哇。我想略读不会一直工作得那么好。以后我会努力花更多时间实际阅读。
猜你喜欢
  • 1970-01-01
  • 2016-12-16
  • 1970-01-01
  • 2019-04-23
  • 2015-12-20
  • 1970-01-01
  • 1970-01-01
  • 2020-04-26
相关资源
最近更新 更多