在多个 std::bitset 中计算 1 出现的最快方法<N>?
Fastest way of counting occurences of 1's in multiple std::bitset<N>?
我想计算1
在多个位集中在同一位置的出现次数。每个位置的计数存储在一个vector中。
。
b0 = 1011
b1 = 1110
b2 = 0110
----
c = 2231 (1+1+0,0+1+1,1+1+1,1+0+0)
我可以用下面的代码轻松地做到这一点,但这段代码似乎缺乏性能,但我不确定。所以我的问题很简单:有没有更快的方法来计算1
?
#include <bitset>
#include <vector>
#include <iostream>
#include <string>
int main(int argc, char ** argv)
{
std::vector<std::bitset<4>> bitsets;
bitsets.push_back(std::bitset<4>("1011"));
bitsets.push_back(std::bitset<4>("1110"));
bitsets.push_back(std::bitset<4>("0110"));
std::vector<unsigned> counts;
for (int i=0,j=4; i<j; ++i)
{
counts.push_back(0);
for (int p=0,q=bitsets.size(); p<q; ++p)
{
if (bitsets[p][(4-1)-i]) // reverse order
{
counts[i] += 1;
}
}
}
for (auto const & count: counts)
{
std::cout << count << " ";
}
}
for (int i=0,j=4; i<j; ++i)
{
for (int p=0,q=b.size(); p<q; ++p)
{
if(b[p][i])
{
c[p] += 1;
}
}
}
表驱动的方法。显然,它有其局限性*,但根据应用程序可以证明是非常合适的:
#include <array>
#include <bitset>
#include <string>
#include <iostream>
#include <cstdint>
static const uint32_t expand[] = {
0x00000000,
0x00000001,
0x00000100,
0x00000101,
0x00010000,
0x00010001,
0x00010100,
0x00010101,
0x01000000,
0x01000001,
0x01000100,
0x01000101,
0x01010000,
0x01010001,
0x01010100,
0x01010101
};
int main(int argc, char* argv[])
{
std::array<std::bitset<4>, 3> bits = {
std::bitset<4>("1011"),
std::bitset<4>("1110"),
std::bitset<4>("0110")
};
uint32_t totals = 0;
for (auto& x : bits)
{
totals += expand[x.to_ulong()];
}
std::cout << ((totals >> 24) & 0xff) << ((totals >> 16) & 0xff) << ((totals >> 8) & 0xff) << ((totals >> 0) & 0xff) << std::
endl;
return 0;
}
编辑:*实际上,它比人们想象的要少… 我个人会改变你排序的方式。
1011 110
1110 becomes 011
0110 111
100
两个主要原因:你可以使用stl算法,并且当你处理更大的数据时,可以使用数据局域性来提高性能。
#include <bitset>
#include <vector>
#include <iostream>
#include <string>
#include <iterator>
int main()
{
std::vector<std::bitset<3>> bitsets_transpose;
bitsets_transpose.reserve(4);
bitsets_transpose.emplace_back(std::bitset<3>("110"));
bitsets_transpose.emplace_back(std::bitset<3>("011"));
bitsets_transpose.emplace_back(std::bitset<3>("111"));
bitsets_transpose.emplace_back(std::bitset<3>("100"));
std::vector<size_t> counts;
counts.reserve(4);
for (auto &el : bitsets_transpose) {
counts.emplace_back(el.count()); // use bitset::count()
}
// print counts result
std::copy(counts.begin(), counts.end(), std::ostream_iterator<size_t>(std::cout, " "));
}
生活代码
输出
2 2 3 1
通过重构将计数逻辑从向量管理中分离出来,我们可以检查计数算法的效率:
#include <bitset>
#include <vector>
#include <iostream>
#include <string>
#include <iterator>
__attribute__((noinline))
void count(std::vector<unsigned> counts,
const std::vector<std::bitset<4>>& bitsets)
{
for (int i=0,j=4; i<j; ++i)
{
for (int p=0,q=bitsets.size(); p<q; ++p)
{
if (bitsets[p][(4-1)-i]) // reverse order
{
counts[i] += 1;
}
}
}
}
int main(int argc, char ** argv)
{
std::vector<std::bitset<4>> bitsets;
bitsets.push_back(std::bitset<4>("1011"));
bitsets.push_back(std::bitset<4>("1110"));
bitsets.push_back(std::bitset<4>("0110"));
std::vector<unsigned> counts(bitsets.size(), 0);
count(counts, bitsets);
for (auto const & count: counts)
{
std::cout << count << " ";
}
}
gcc5.3 with -O2生成如下:
count(std::vector<unsigned int, std::allocator<unsigned int> >, std::vector<std::bitset<4ul>, std::allocator<std::bitset<4ul> > > const&):
movq (%rsi), %r8
xorl %r9d, %r9d
movl $3, %r10d
movl $1, %r11d
movq 8(%rsi), %rcx
subq %r8, %rcx
shrq $3, %rcx
.L4:
shlx %r10, %r11, %rsi
xorl %eax, %eax
testl %ecx, %ecx
jle .L6
.L10:
testq %rsi, (%r8,%rax,8)
je .L5
movq %r9, %rdx
addq (%rdi), %rdx
addl $1, (%rdx)
.L5:
addq $1, %rax
cmpl %eax, %ecx
jg .L10
.L6:
addq $4, %r9
subl $1, %r10d
cmpq $16, %r9
jne .L4
ret
这对我来说一点也不低效。
您的程序中存在冗余内存重新分配和其他一些代码。例如,在使用push_back
方法之前,您可以首先在vector中预留足够的内存。
程序可以如下所示:
#include <iostream>
#include <bitset>
#include <vector>
const size_t N = 4;
int main()
{
std::vector<std::bitset<N>> bitsets =
{
std::bitset<N>( "1011" ),
std::bitset<N>( "1110" ),
std::bitset<N>( "0110" )
};
std::vector<unsigned int> counts( N );
for ( const auto &b : bitsets )
{
for ( size_t i = 0; i < N; i++ ) counts[i] += b[N - i -1];
}
for ( unsigned int val : counts ) std::cout << val;
std::cout << std::endl;
return 0;
}
输出为
2231
相关文章:
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- C / CUDA中的模板方法是3个角括号(&lt;&lt;&lt;)
- 超载&LT的正确方法;操作员