Concatenate boost::dynamic_bitset or std::bitset

后端 未结 5 1960
梦毁少年i
梦毁少年i 2020-12-16 19:57

what is the best way to concatenate 2 bitsets?

For example i\'ve got

boost::dynamic_bitset<> test1( std::string(\"1111\") );
boost::dynamic_bit         


        
相关标签:
5条回答
  • 2020-12-16 20:34

    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;
    }
    
    0 讨论(0)
  • 2020-12-16 20:40

    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

    0 讨论(0)
  • 2020-12-16 20:43

    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;
    }
    
    0 讨论(0)
  • 2020-12-16 20:46

    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.

    0 讨论(0)
  • 2020-12-16 20:53

    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.

    0 讨论(0)
提交回复
热议问题