【问题标题】:Fast AND operation on bit arrays位数组上的快速与运算
【发布时间】:2020-06-03 07:20:01
【问题描述】:

在大型位数组上进行按位与运算的更快算法是什么?我已经使用 char 数组在 C++ 中实现了位数组。现在,我正在遍历每个字节并执行 AND 操作。

void ANDoperation(char* A, char* B){
  for (int i=0; i<(array_size/8 +1); i++ ){
    A[i] &= B[i];
  }
}

对于 K 个数组,我正在迭代执行此函数 K-1 次。

【问题讨论】:

  • 您对“速度”和“效率”的要求是什么?这是否被认为是您程序的主要(前两个)瓶颈?您是否在启用编译器优化的情况下完成了测量和基准测试?
  • 如果您知道您的数组已正确对齐,并且它们的长度超过 2 或 4 个字节,您可以在 uint16_tuint32_tuint64_t 的块中执行 AND(在更复杂的代码的成本)。
  • @Someprogrammerdude 是的。我尝试过 O2 优化。这是瓶颈。在我的情况下,位数组大小是 > 10^6。
  • O2 可能不会开启矢量化。试试O3,并考虑让你的指针restricted。如果没有restrict,可能会避免矢量化。正确对齐数组以进行矢量化可能也是一个好主意(例如,在 AVX-512 的 64 位边界处)。这个问题可能是相关的:How to tell GCC that a pointer argument is always double-word-aligned?你如何衡量它是一个瓶颈? 10^6 是一个非常小的数组。
  • 在此处比较这些版本:godbolt.org/z/hedNBo。您可以观察到,在第二种情况下,循环中的指令数量最少(1x 向量寄存器加载、1x 和 1x 存储)。

标签: c++ arrays char bitarray bitwise-and


【解决方案1】:

如果您想采用更 C++ 的方式,我建议您按以下方式使用 std::bitset

#include <iostream>
#include <bitset>

int main()  {
    std::bitset<3> v1(0b110);
    std::bitset<3> v2(0b011);

    v1 &= v2;

    std::cout << v1.to_string() << std::endl; // 010

    return 0;
}

Demo

或如@AndrewBainbridge 建议的那样:

void and_operation(std::bitset<3000>& v1, std::bitset<3000> const& v2) {
    v1 &= v2;
}

【讨论】:

  • 您没有指定-O3,所以没有进行优化。但是即使进行了优化,这也会导致非常糟糕的性能,因为std::vector&lt;bool&gt; 是一种在位上运行的专业化。只需检查输出程序集,您会看到没有完成矢量化
  • 演示链接(指向 Godbolt 会话)显示编译器在编译时评估了 AND。这是一个更好的会话:godbolt.org/z/XN5k5u
  • bitset 的长度需要很大,否则编译器会在一条指令中完成整个数组。在我的示例中,我将长度设置为 3000。生成的代码是一个循环,每次迭代处理 64 位。
  • @AndrewBainbridge 是的,你是对的。我放 3 只是作为示例,但会放 3000。谢谢
  • 另外,“在你的情况下”可能比“在安德鲁的情况下”更好,因为我们已经有两个评论者了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-10
  • 1970-01-01
  • 2013-01-21
  • 2012-08-03
  • 1970-01-01
  • 2012-07-07
相关资源
最近更新 更多