二进制数组的快速Popcount指令或汉明距离?

时间:2012-07-05 01:07:43

标签: c++ performance bit-manipulation hamming-distance

我正在Visual Studio 2010 C ++上实现

我有两个二进制数组。例如,

array1[100] = {1,0,1,0,0,1,1, .... }
array2[100] = {0,0,1,1,1,0,1, .... }

要计算array1array2之间的Hamming distancearray3[100]存储xorarray1的{​​{1}}结果。

然后我必须计算array21位的数量。为此,我知道我可以使用array3指令。

现在,我正在做类似下面的事情:

__popcnt

它显示了良好的结果,但速度很慢。我怎样才能让它更快?

3 个答案:

答案 0 :(得分:3)

array3似乎有点浪费,你正在访问一个你不需要的额外400字节的内存。我会尝试比较你的以下内容:

for (int i = 0; i < 100; ++i) {
    result += (array1[i] ^ array2[i]);   // could also try != in place of ^
}

如果这有帮助,那么我将其作为练习留给读者如何应用此更改 duskwuff's。

答案 1 :(得分:2)

实施后,__popcnt电话无效。它实际上让你慢下来。

__popcnt计算其参数中的设置位数。你只传递一个元素,看起来它保证为0或1,所以结果(也是0或1)没用。这样做会稍快一些:

popcnt_result += array3[i];

根据阵列的布局方式,您可能会或可能无法以更聪明的方式使用__popcnt。具体来说,如果您的数组由一个字节的元素组成(例如charboolint8_t或类似的元素),您可以一次对四个元素执行一次人口统计:< / p>

for(i = 0; i < 100; i += 4) {
    uint32_t *p = (uint32_t *) &array3[i];
    popcnt_result += __popcnt(*p);
}

(请注意,这取决于100可以被4整除的事实。否则你必须为最后几个元素添加一些特殊情况处理。)

如果数组包含较大的值,例如int,那么你运气不好,而且仍然无法保证这比上面的天真实现更快。

答案 2 :(得分:1)

如果您的数组只包含两个值(01),则汉明距离只是相应值不同的位置数。这可以使用标准库中的std::inner_product一次完成。

#include <iostream>
#include <functional>
#include <numeric>

int main()
{
    int array1[100] = { 1,0,1,0,0,1,1, ... };
    int array2[100] = { 0,0,1,1,1,0,1, ... };

    int distance = std::inner_product(array1, array1 + 100, array2, 0, std::plus<int>(), std::not_equal_to<int>());

    std::cout << "distance=" << distance << '\n';

    return 0;
}