连接 boost::dynamic_bitset 或 std::bitset

发布于 2024-09-06 12:20:08 字数 573 浏览 7 评论 0原文

连接 2 个位集的最佳方法是什么?

例如,我知道

boost::dynamic_bitset<> test1( std::string("1111") );
boost::dynamic_bitset<> test2( std::string("00") );

它们应该连接到第三个位集 test3 中,然后它保存

111100 

解决方案应该使用 boost::dynamic_bitset。如果该解决方案适用于 std::bitset,那就太好了。连接位时应关注性能。

更新: 我比较了这两种方法(我和 Neil 的 stringmethod 以及 Messenger 的 shiftmethod),并且 stringmethod 更快(因子 10++)。代码在这里: http://pastebin.com/HfpfYfy8

我希望 Pastebin 可以发布长代码列表。如果有更好的方法请联系我。

what is the best way to concatenate 2 bitsets?

For example i've got

boost::dynamic_bitset<> test1( std::string("1111") );
boost::dynamic_bitset<> test2( std::string("00") );

they should be concatenated into a thrid Bitset test3 which then holds

111100 

Solutions should use boost::dynamic_bitset. If the solution works with std::bitset, it would be nice too. There should be a focus on performance when concatenating the bits.

UPDATE:
I've compared both methods (stringmethod from me and Neil and shiftmethod from messenger) and the stringmethod was a lot faster (factor 10++). Code here:
http://pastebin.com/HfpfYfy8

I hope Pastebin is ok for posting long code-listings. If there is a better way please contact me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

南烟 2024-09-13 12:20:08

对于标准位集,类似于:

#include <bitset>
#include <string>
#include <iostream>
using namespace std;

template <size_t N1, size_t N2 >
bitset <N1 + N2> concat( const bitset <N1> & b1, const bitset <N2> & b2 ) {
    string s1 = b1.to_string();
    string s2 = b2.to_string();
    return bitset <N1 + N2>( s1 + s2 );
}

int main() {
    bitset <4> a( string("1010") );
    bitset <2> b( string("11") );
    cout << concat( a, b ) << endl;
}

For the standard bitset, something like:

#include <bitset>
#include <string>
#include <iostream>
using namespace std;

template <size_t N1, size_t N2 >
bitset <N1 + N2> concat( const bitset <N1> & b1, const bitset <N2> & b2 ) {
    string s1 = b1.to_string();
    string s2 = b2.to_string();
    return bitset <N1 + N2>( s1 + s2 );
}

int main() {
    bitset <4> a( string("1010") );
    bitset <2> b( string("11") );
    cout << concat( a, b ) << endl;
}
月亮邮递员 2024-09-13 12:20:08

我已经测试了几种解决方案,似乎:

  • 一个好的旧“for循环”是最快的
  • 位集,比dynamic_bitset快很多(不足为奇),如果不需要内存分配,开销会较低,但仍然存在。
  • 这看起来似乎很明显,但是直接将一个位集附加到另一个位集而不创建新的位集会更快。如果您需要保持第一个位集不变(也很明显),则此解决方案不适合。
  • 这 3 种解决方案不会产生相同的结果,您必须根据需要进行一些调整(见下文)。

这是我的测试代码:

#include <iostream>
#include <bitset>
#include <boost/dynamic_bitset/dynamic_bitset.hpp>
#include "scul/PreciseTimer.h"

boost::dynamic_bitset<> concatOperatorsDyn( const boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2)
{
    boost::dynamic_bitset<> bs1Copy(bs1);
    boost::dynamic_bitset<> bs2Copy(bs2);
    size_t totalSize=bs1.size()+bs2.size();
    bs1Copy.resize(totalSize);
    bs2Copy.resize(totalSize);
    bs1Copy<<=bs2.size();
    bs1Copy|=bs2Copy;
    return bs1Copy;
}

template<size_t sRes,size_t s1,size_t s2>
std::bitset<sRes> concatString( const std::bitset<s1>& bs1,const std::bitset<s2>& bs2)
{
    std::string s1=bs1.to_string<char,std::char_traits<char>,std::allocator<char> >();
    std::string s2=bs2.to_string<char,std::char_traits<char>,std::allocator<char> >();

    std::bitset<sRes> res(s1+s2);
    return res;
}

template<size_t sRes,size_t s1,size_t s2>
std::bitset<sRes> concatLoop( const std::bitset<s1>& bs1,const std::bitset<s2>& bs2)
{
    std::bitset<sRes> res;
    for(size_t i=0;i<s1;i++)
        res[i]=bs1[i];

    for(size_t i=0;i<s2;i++)
        res[i+s1]=bs2[i];
    return res;
}
boost::dynamic_bitset<> concatLoopDyn( const boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2)
{
boost::dynamic_bitset<> res(bs1);
res.resize(bs1.size()+bs2.size());
    size_t bs1Size=bs1.size();
    size_t bs2Size=bs2.size();

    for(size_t i=0;i<bs2.size();i++)
        res[i+bs1Size]=bs2[i];
    return res;
}
boost::dynamic_bitset<> concatStringDyn( const boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2)
{
    std::string s1;
    std::string s2;
    to_string(bs1,s1);
    to_string(bs2,s2);

    boost::dynamic_bitset<> res(s1+s2);
    return res;
}


template<size_t s1,size_t s2>
void injectLoop( std::bitset<s1>& bs1,const std::bitset<s2>& bs2,int start=s1-s2)
{
    for(size_t i=0;i<s2;i++)
        bs1[i+start]=bs2[i];
}


void injectLoopDyn( boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2,int start)
{
    for(size_t i=0;i<bs2.size();i++)
        bs1[i+start]=bs2[i];
}

void testBitstream()
{
    const std::bitset<20> bs1(std::string("11111111110000000000"));
    std::bitset<30> bs1Bis(std::string("11111111110000000000"));
    const std::bitset<10> bs2(std::string("0000011111"));
    std::bitset<30> bs3;


    const boost::dynamic_bitset<> bs1D(std::string("11111111110000000000"));
    boost::dynamic_bitset<> bs1DBis(std::string("11111111110000000000"));
    bs1DBis.resize(30);
    const boost::dynamic_bitset<> bs2D(std::string("0000011111"));
    boost::dynamic_bitset<> bs3D;

    scul::PreciseTimer t;
    double d=0.;

    int nbIter=100;

    std::cout<<"Bitset concat with strings"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3=concatString<30,20,10>(bs1,bs2);
    d=t.stop();
    std::cout<<bs3.to_string<char,std::char_traits<char>,std::allocator<char> >()<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;;


    std::cout<<"Bitset concat with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3=concatLoop<30,20,10>(bs1,bs2);
    d=t.stop();
    std::cout<<bs3.to_string<char,std::char_traits<char>,std::allocator<char> >()<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;

    std::cout<<"Bitset inject with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        injectLoop<30,10>(bs1Bis,bs2);
    d=t.stop();
    std::cout<<bs1Bis.to_string<char,std::char_traits<char>,std::allocator<char> >()<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;


    std::cout<<"Dynamicbitset concat with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3D=concatLoopDyn(bs1D,bs2D);
    d=t.stop();
    std::string s;
    to_string(bs3D,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;


    std::cout<<"Dynamicbitset inject with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        injectLoopDyn(bs1DBis,bs2D,20);
    d=t.stop();
    to_string(bs1DBis,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;

    std::cout<<"Dynamicbitset concat with operators"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3D=concatOperatorsDyn(bs1D,bs2D);
    d=t.stop();
    to_string(bs3D,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;


    std::cout<<"Dynamicbitset concat with strings"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3D=concatStringDyn(bs1D,bs2D);
    d=t.stop();
    to_string(bs3D,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;

}

这是我在计算机上使用 VS7.1 得到的输出:

Bitset concat with strings
111111111100000000000000011111
duration=0.000366713

Bitset concat with loop
000001111111111111110000000000
duration=7.99985e-006

Bitset inject with loop
000001111111111111110000000000
duration=2.87995e-006

Dynamicbitset concat with loop
000001111111111111110000000000
duration=0.000132158

Dynamicbitset inject with loop
000001111111111111110000000000
duration=3.19994e-006

Dynamicbitset concat with operators
111111111100000000000000011111
duration=0.000191676

Dynamicbitset concat with strings
111111111100000000000000011111
duration=0.000404152

您可以注意到我使用循环编写的函数产生了不同的结果。这是因为我当时写的是将第二个位集的 lsb 放在第一个位集的 msb 之后(lsb 在右侧)。使用字符串或“位运算符”功能,您只需切换调用参数即可。

I've tested several solutions and it seems that :

  • a good old "for loop" is the fastest
  • bitset is a lot faster than dynamic_bitset (not surprising), if no memory allocation is needed the overhead is lower but still exists.
  • It may seems obvious but, directly append a bitset to another without creating a new one is a faster. This solution is not suitable if you need to keep the first bitset unchanged (obvious too).
  • The 3 solutions don't produces the same result, you have to do some tuning depending on want you want(see below).

Here is my test code :

#include <iostream>
#include <bitset>
#include <boost/dynamic_bitset/dynamic_bitset.hpp>
#include "scul/PreciseTimer.h"

boost::dynamic_bitset<> concatOperatorsDyn( const boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2)
{
    boost::dynamic_bitset<> bs1Copy(bs1);
    boost::dynamic_bitset<> bs2Copy(bs2);
    size_t totalSize=bs1.size()+bs2.size();
    bs1Copy.resize(totalSize);
    bs2Copy.resize(totalSize);
    bs1Copy<<=bs2.size();
    bs1Copy|=bs2Copy;
    return bs1Copy;
}

template<size_t sRes,size_t s1,size_t s2>
std::bitset<sRes> concatString( const std::bitset<s1>& bs1,const std::bitset<s2>& bs2)
{
    std::string s1=bs1.to_string<char,std::char_traits<char>,std::allocator<char> >();
    std::string s2=bs2.to_string<char,std::char_traits<char>,std::allocator<char> >();

    std::bitset<sRes> res(s1+s2);
    return res;
}

template<size_t sRes,size_t s1,size_t s2>
std::bitset<sRes> concatLoop( const std::bitset<s1>& bs1,const std::bitset<s2>& bs2)
{
    std::bitset<sRes> res;
    for(size_t i=0;i<s1;i++)
        res[i]=bs1[i];

    for(size_t i=0;i<s2;i++)
        res[i+s1]=bs2[i];
    return res;
}
boost::dynamic_bitset<> concatLoopDyn( const boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2)
{
boost::dynamic_bitset<> res(bs1);
res.resize(bs1.size()+bs2.size());
    size_t bs1Size=bs1.size();
    size_t bs2Size=bs2.size();

    for(size_t i=0;i<bs2.size();i++)
        res[i+bs1Size]=bs2[i];
    return res;
}
boost::dynamic_bitset<> concatStringDyn( const boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2)
{
    std::string s1;
    std::string s2;
    to_string(bs1,s1);
    to_string(bs2,s2);

    boost::dynamic_bitset<> res(s1+s2);
    return res;
}


template<size_t s1,size_t s2>
void injectLoop( std::bitset<s1>& bs1,const std::bitset<s2>& bs2,int start=s1-s2)
{
    for(size_t i=0;i<s2;i++)
        bs1[i+start]=bs2[i];
}


void injectLoopDyn( boost::dynamic_bitset<>& bs1,const boost::dynamic_bitset<>& bs2,int start)
{
    for(size_t i=0;i<bs2.size();i++)
        bs1[i+start]=bs2[i];
}

void testBitstream()
{
    const std::bitset<20> bs1(std::string("11111111110000000000"));
    std::bitset<30> bs1Bis(std::string("11111111110000000000"));
    const std::bitset<10> bs2(std::string("0000011111"));
    std::bitset<30> bs3;


    const boost::dynamic_bitset<> bs1D(std::string("11111111110000000000"));
    boost::dynamic_bitset<> bs1DBis(std::string("11111111110000000000"));
    bs1DBis.resize(30);
    const boost::dynamic_bitset<> bs2D(std::string("0000011111"));
    boost::dynamic_bitset<> bs3D;

    scul::PreciseTimer t;
    double d=0.;

    int nbIter=100;

    std::cout<<"Bitset concat with strings"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3=concatString<30,20,10>(bs1,bs2);
    d=t.stop();
    std::cout<<bs3.to_string<char,std::char_traits<char>,std::allocator<char> >()<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;;


    std::cout<<"Bitset concat with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3=concatLoop<30,20,10>(bs1,bs2);
    d=t.stop();
    std::cout<<bs3.to_string<char,std::char_traits<char>,std::allocator<char> >()<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;

    std::cout<<"Bitset inject with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        injectLoop<30,10>(bs1Bis,bs2);
    d=t.stop();
    std::cout<<bs1Bis.to_string<char,std::char_traits<char>,std::allocator<char> >()<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;


    std::cout<<"Dynamicbitset concat with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3D=concatLoopDyn(bs1D,bs2D);
    d=t.stop();
    std::string s;
    to_string(bs3D,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;


    std::cout<<"Dynamicbitset inject with loop"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        injectLoopDyn(bs1DBis,bs2D,20);
    d=t.stop();
    to_string(bs1DBis,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;

    std::cout<<"Dynamicbitset concat with operators"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3D=concatOperatorsDyn(bs1D,bs2D);
    d=t.stop();
    to_string(bs3D,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;


    std::cout<<"Dynamicbitset concat with strings"<<std::endl;
    t.start();
    for(int i=0;i<nbIter;++i)
        bs3D=concatStringDyn(bs1D,bs2D);
    d=t.stop();
    to_string(bs3D,s);
    std::cout<<s<<std::endl;
    std::cout<<"duration="<<d<<std::endl<<std::endl;

}

Here is the output I get with VS7.1 on my computer:

Bitset concat with strings
111111111100000000000000011111
duration=0.000366713

Bitset concat with loop
000001111111111111110000000000
duration=7.99985e-006

Bitset inject with loop
000001111111111111110000000000
duration=2.87995e-006

Dynamicbitset concat with loop
000001111111111111110000000000
duration=0.000132158

Dynamicbitset inject with loop
000001111111111111110000000000
duration=3.19994e-006

Dynamicbitset concat with operators
111111111100000000000000011111
duration=0.000191676

Dynamicbitset concat with strings
111111111100000000000000011111
duration=0.000404152

You can notice that the function I wrote using loops produce differents results. It's because I wrote then to put the lsb of the second bitset after the msb of the first one (lsb on the right). With the string or "bit operator" function you just have to switch the calling parameters.

舟遥客 2024-09-13 12:20:08

我运行了一个测试,比较以下两种方法:

  /* ... */
  for( int ii = 0; ii < 1000000; ++ii ) {
    std::bitset<16> v1( randomUlongs[ii] );
    std::bitset<16> v2( randomUlongs[ii+1] );
#ifdef STRING_TEST
    std::bitset<32> v3( v1.to_string() + v2.to_string() );
#else
    std::bitset<32> v3( v2.to_ulong() | (v1.to_ulong() << 16) );
    /* print out v3 */
  }

... 其中 randomUlongs 在每次运行期间都是恒定的(标头中的大数组)以避免任何污染结果。我用以下方法计时:

~ time for ((ii=0; ii<1000; ii++)); do ./bitset_test >/dev/null; done

在 Linux (x86_i686) 下,使用 gcc 4.4.6 优化级别 3:字符串连接速度最快,为 2 倍。

在 Solaris (sparc) 下,使用 gcc 3.4 .3Sun Studio C++ 5.12 (2011/11/16),两者的优化级别都是 3:非字符串方法的速度快了 10 倍。

我想您会找到“最快”的解决方案高度依赖于编译器,尽管我认为平台也可以发挥重要作用。

I ran a test comparing the following two approaches:

  /* ... */
  for( int ii = 0; ii < 1000000; ++ii ) {
    std::bitset<16> v1( randomUlongs[ii] );
    std::bitset<16> v2( randomUlongs[ii+1] );
#ifdef STRING_TEST
    std::bitset<32> v3( v1.to_string() + v2.to_string() );
#else
    std::bitset<32> v3( v2.to_ulong() | (v1.to_ulong() << 16) );
    /* print out v3 */
  }

... where randomUlongs was constant during each run (a large array in a header) to avoid anything contaminating results. I timed it with:

~ time for ((ii=0; ii<1000; ii++)); do ./bitset_test >/dev/null; done

Under Linux (x86_i686) with gcc 4.4.6 at optimization level 3: the string concatenation was fastest, by a factor of 2.

Under Solaris (sparc) with gcc 3.4.3 and Sun Studio C++ 5.12 (2011/11/16), both with optimization level 3: the non-string approach was fastest by a factor of 10.

I think you'll find the "fastest" solution is highly dependent on the compiler, though I suppose platform could play a significant role as well.

夏夜暖风 2024-09-13 12:20:08

首先,我将自己添加一个可能的解决方案。以下代码使用了使用 std::string 构造位集并从位集生成 std​​::string 的可能性。

#include <sstream>  // for std::ostringstream
#include <boost/dynamic_bitset.hpp>

boost::dynamic_bitset<> test1( std::string("1111") );
boost::dynamic_bitset<> test2( std::string("00") );

std::ostringstream bitsetConcat;
bitsetConcat << test1 << test2;
boost::dynamic_bitset<> test3( bitsetConcat.str() );

std::cout << test3 << std::endl;

这可行,但必须有其他更高效的解决方案...

更新:
感谢 JC Leitão 的编辑建议

For getting started, i'll add a possible solution by myself. The following code uses the possibility to construct bitsets with std::string and to generate a std::string from a bitset.

#include <sstream>  // for std::ostringstream
#include <boost/dynamic_bitset.hpp>

boost::dynamic_bitset<> test1( std::string("1111") );
boost::dynamic_bitset<> test2( std::string("00") );

std::ostringstream bitsetConcat;
bitsetConcat << test1 << test2;
boost::dynamic_bitset<> test3( bitsetConcat.str() );

std::cout << test3 << std::endl;

This works, but there must be other, more performant solutions...

Update:
Thanks to J. C. Leitão for his edit-suggestion

你げ笑在眉眼 2024-09-13 12:20:08

这是一个解决方案。不确定是否可以编译。

typedef boost::dynamic_bitset<> Bits;

Bits Concatenate(const Bits& first, const Bits& second)
{
    Bits value(first);

    //Increase the size of the bit buffer to fit the data being placed in it
    value.resize(first.size() + second.size());
    value <<= second.size();
    value |= second;
    return value;
}

Here is a stab at a solution. Not sure if it compiles.

typedef boost::dynamic_bitset<> Bits;

Bits Concatenate(const Bits& first, const Bits& second)
{
    Bits value(first);

    //Increase the size of the bit buffer to fit the data being placed in it
    value.resize(first.size() + second.size());
    value <<= second.size();
    value |= second;
    return value;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文