这是我的问题:
我需要在C
或C++11
中非常有效地完成此操作(我需要在超级计算机上执行此操作数十亿次)。 N
和n
在编译时已知(模板参数)。最有效的算法是什么?
以下是一个例子:
#include <iostream>
#include <climits>
#include <type_traits>
#include <bitset>
template <unsigned int Modulo,
typename Type,
unsigned int Size = sizeof(Type)*CHAR_BIT,
class = typename std::enable_if<std::is_integral<Type>::value
&& std::is_unsigned<Type>::value>::type>
inline Type f(Type x)
{
// The most inefficient algorithm ever
std::bitset<Size> bx(x);
std::bitset<Size> by(0);
unsigned int j = 0;
for (unsigned int i = 0; i < Size; ++i) {
if (i%Modulo) {
by[j++] = bx[i];
}
}
return by.to_ullong();
}
int main()
{
std::bitset<64> x = 823934823;
std::cout<<x<<std::endl;
std::cout<<(std::bitset<64>(f<2>(x.to_ullong())))<<std::endl;
return 0;
}
答案 0 :(得分:2)
语义上(从概念上讲,因为你实际上不能在这里使用迭代器),你正在做一个std::copy_if
,你的输入和输出范围是std::bitset<N>
,你的谓词是表格的lambda (使用C ++ 14通用lambda表示法)
[](auto elem) { return elem % n != 0; }
此算法在分配数量和谓词调用次数方面具有O(N)
的复杂性。因为std::bitset<N>
没有迭代器,所以必须逐位检查。这意味着带有手写谓词的循环与假设的可迭代std::copy_if
上的std::bitset<N>
完全相同。
这意味着就渐远效率而言,您的算法不应被视为低效。
因此,如果您的算法没有像二次复杂度那样做任何不好的结论,那么它的常数因子能够被优化吗? std::bitset
效率的主要来源是您的硬件可以并行处理多个(8,16,32或64)位。如果您有权访问该实现,则可以编写自己的copy_if
来利用该并行性,例如通过特殊的硬件指令,查找表或一些bit-twiddling algorithm。
E.g。这是成员函数count()
以及gcc和SGI扩展Find_first_()
和Find_next_()
的实现方式。旧的SGI实现使用256个条目的查找表来处理每个8位char
的位上的位计数和准迭代。最新的gcc版本使用__builtin_popcountll()
和__builtin_ctzll()
为每个64位字进行填充计数和位查找。
不幸的是,std::bitset
没有暴露其无符号整数的底层数组。因此,如果您想改进已发布的算法,则需要编写自己的BitSet
类模板(可通过调整自己的标准库的来源)并为其提供成员函数copy_if
(或类似)利用你的硬件。与当前算法相比,它可以提高8到64倍的效率。