【发布时间】:2014-10-13 02:40:55
【问题描述】:
我最近遇到了 bitset 模板,我真的很想在我当前的项目中使用它们。继续阅读,我看到std::bitset 模板的大小必须在编译时确定。许多人建议使用boost::dynamic_bitset 来缓解这一要求。
为了比较两者,我决定对set、flip 和count 方法进行速度比较。
结果很奇怪......我想知道是否有人可以为我解释一下。
代码在帖子的末尾,但我会在这里解释我在做什么。我有一个std::bitset 对象(称为bs)和一个boost::dynamic_bitset 对象(称为dynbs)。每个都有n=1000000 位。对于上面的给定方法,依次调用每个n 位上的方法并重复此R=10000 次。
使用std::chrono 库,以下是每个以纳秒为单位的计时:
set
bitset: 267 nsecs
dyn bitset: 18603174546 nsecs
flip
bitset: 73 nsecs
dyn bitset: 18842352867 nsecs
count
bitset: 77 nsecs
dyn bitset: 51 nsecs
对于set 和flip,boost::dynamic_bitset 似乎要慢得多。
为了更有趣,如果在运行这些测试之前对两个对象调用方法reset,那么时间是可比较的。他们在这里:
set
bitset: 19397779399 nsecs
dyn bitset: 18472863864 nsecs
flip
bitset: 18599248629 nsecs
dyn bitset: 18376267939 nsecs
count
bitset: 68 nsecs
dyn bitset: 61 nsecs
现在,两个容器都声称将所有位初始化为0,因此对reset 的调用不应更改任何位。在reset 之前和之后转储none 的输出确实证实了这一点。
毕竟,我有两个问题:
1) 为什么在调用set 和flip 时boost::dynamic_bitset 比std::bitset 慢很多?
2) 为什么调用reset会对std::bitset的速度产生巨大的负面影响?
这是我的代码:
#include <iostream>
#include <iomanip>
#include <bitset>
#include <boost/dynamic_bitset.hpp>
#include <vector>
#include <chrono>
#include <ctime>
using namespace std;
using namespace chrono;
using namespace boost;
int main(){
const unsigned int n=1000000;
bitset< n > bs;
dynamic_bitset< > dynbs(n);
// bs.reset();
// dynbs.reset();
unsigned int i,r,R=10000;
high_resolution_clock::time_point tick,tock;
////////////////////////////////////////////////////////////
// Method: set
std::cout << "set" << std::endl;
tick=high_resolution_clock::now();
for(r=0; r<R; r++)
for(i=0; i<n; i++)
bs.set(i);
tock=high_resolution_clock::now();
cout << setw(16) << "bitset: "
<< setw(16) << duration_cast<nanoseconds>(tock-tick).count() << " nsecs"
<< std::endl;
tick=high_resolution_clock::now();
for(r=0; r<R; r++)
for(i=0; i<n; i++)
dynbs.set(i);
tock=high_resolution_clock::now();
cout << setw(16) << "dyn bitset: "
<< setw(16) << duration_cast<nanoseconds>(tock-tick).count() << " nsecs"
<< std::endl << std::endl;
////////////////////////////////////////////////////////////
// Method: flip
std::cout << "flip" << std::endl;
tick=high_resolution_clock::now();
for(r=0; r<R; r++)
for(i=0; i<n; i++)
bs.flip(i);
tock=high_resolution_clock::now();
cout << setw(16) << "bitset: "
<< setw(16) << duration_cast<nanoseconds>(tock-tick).count() << " nsecs"
<< std::endl;
tick=high_resolution_clock::now();
for(r=0; r<R; r++)
for(i=0; i<n; i++)
dynbs.flip(i);
tock=high_resolution_clock::now();
cout << setw(16) << "dyn bitset: "
<< setw(16) << duration_cast<nanoseconds>(tock-tick).count() << " nsecs"
<< std::endl << std::endl;
////////////////////////////////////////////////////////////
// Method: count
std::cout << "count" << std::endl;
tick=high_resolution_clock::now();
for(r=0; r<R; r++)
for(i=0; i<n; i++)
bs.count();
tock=high_resolution_clock::now();
cout << setw(16) << "bitset: "
<< setw(16) << duration_cast<nanoseconds>(tock-tick).count() << " nsecs"
<< std::endl;
tick=high_resolution_clock::now();
for(r=0; r<R; r++)
for(i=0; i<n; i++)
dynbs.count();
tock=high_resolution_clock::now();
cout << setw(16) << "dyn bitset: "
<< setw(16) << duration_cast<nanoseconds>(tock-tick).count() << " nsecs"
<< std::endl;
return 0;
}
我用它编译过
g++ -O3 -std=c++11 bitset.cpp -o bitset
bitset.cpp 是上面插入的代码。
【问题讨论】:
-
@T.C.只是我的测试太简单了吗?我想我不太确定这意味着什么。我试图阅读汇编代码,但不太明白发生了什么。
-
差不多。微基准很难编写。在这种情况下,如果在每个循环之后添加要打印的代码,例如
bs,那么sets 和flips 可能不会被优化掉。为确保count调用不会被优化,请将返回值添加到一个变量中,然后打印出来。dynamic_bitset使用堆上的分配,编译器很难证明set和flip所做的更改将是不可见的。 -
@T.C.明白了。这就说得通了。感谢您澄清幕后发生的事情。刚刚添加了你提到的一些东西,现在看起来是一场公平的战斗!我将发布一个引用您所说的解决方案并将其标记为已解决。
标签: c++ boost-dynamic-bitset std-bitset