快速计算C中的汉明距离

时间:2014-08-02 20:13:19

标签: c gcc intrinsics hamming-distance

我在Hamming Weight上阅读了维基百科的文章并发现了一些有趣的内容:

  

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

     

[强调我的]

我发生了什么事。我可以通过 XOR 计算两个琴弦之间的汉明距离,然后取结果字符串的汉明重量(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

应该更快,特别是一旦内联。


但回到最初的问题。你能把两个弦的XOR的汉明重量找到它们的汉明距离吗?即:

HD = HW (x xor y)

2 个答案:

答案 0 :(得分:5)

两个相等长度的字符串xy之间的汉明距离定义为它们不同的位置数。如果xy是位串,x^y是一个字符串1 s,它们的位置完全相同。因此,HammingDistance(x,y) = Number of 1s in x^y,用于位串。此外,HammingWeight(x) = number of 1s in x表示位串x。因此,您的第一个声明HammingDistance(x,y) = HammingWeight(x^y)适用于位串。确定后,很明显您的实施是正确的。

答案 1 :(得分:3)

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

  

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