1

I am writing my own version of a bitset, because I need one that has dynamic size. Therefore I can't use std::bitset, which is apparently fixed in size.

I now needed to write a method for bitshifting. I found several solutions on how to do bitshifting on arrays or vectors, but none of them was comprehensible to me.

For example the accepted answer in this question:

Bitwise shifting array of char's

No explanation on where the constants 0x07 3 and 5 come from. So I wrote my own method that made sense to me and works. But it has a runtime of O(n), where n is the number of bits in the bitset. And I assume this could be reduced to O(m) where m is the number of ints (or whatever basic type is used to store the bit pattern) in the bitset. Anpther issue is that my method is not in-place and requires e temporary instance of my bitset class.

My code is not really relevant to the question, but it maybe gives it some context.

My method looks like this:

friend BitEncoder& operator<<(BitEncoder& src, int shift)
{
    BitEncoder tmp;
    for (int i = 0; i < src.size(); i++)
    {
        if (src[i])
        {
            tmp(i+shift);
        }
    }
    src = tmp;
    return src;
}

The rest of the class with the irrelevant methods cut out is this:

/**
 * @brief BitEncoder is a dynamic bitset.
 */
class BitEncoder
{
public:
    /**
     * @brief basic constructor
     */
    BitEncoder() {}

    /**
     * @brief alias for setter function
     */
    void operator()(int i)
    {
        set(i);
    }

    /**
     * @brief read-only index operator
     */
    bool operator[](int i)
    {
        unsigned int j = i/(sizeof(int)*8);
        if (j >= bits.size())
        {
            throw 0;
        }
        return (bits[j] & (1 << i));
    }

    /**
     * @brief sets the ith bit
     */
    void set(int i)
    {
        // compute the cell in which the index falls
        unsigned int j = i/(sizeof(int)*8);
        // if the cell is larger than the highest index add as many new cells as
        // necessary
        if (!(j < bits.size()))
        {
            bits.resize(j+1);
        }
        // if the bit is already set, return
        if (bits[j] & (1 << i)) return;
        // set the bit
        bits[j] += (1 << i);
    }

    unsigned size(){return bits.size()*sizeof(int)*8;}

    friend BitEncoder& operator<<(BitEncoder& src, int shift)
    {
        BitEncoder tmp;
        for (int i = 0; i < src.size(); i++)
        {
            if (src[i])
            {
                tmp(i+shift);
            }
        }
        src = tmp;
        return src;
    }

private:

    std::vector<int> bits;

};

Ok, so much for the context. I know this question is kind of a duplicate, but as I said, the answers I found so far are not understandable to me.

Could somebody explain in a more comprehensive manner on the example of a std::vector, like I used in my class to store the bit pattern, ow to perform a bitshift on a vector / array?

Community
  • 1
  • 1
lo tolmencre
  • 3,804
  • 3
  • 30
  • 60
  • 2
    Use the `std::vector` specialisation? – Bathsheba Aug 16 '16 at 06:53
  • 1
    O(n) is the same as O(m) in this case. – nwp Aug 16 '16 at 06:55
  • `O(n) ... O(m)` given that `n = km`, where `k` is a constant, they are the same thing. – n. m. could be an AI Aug 16 '16 at 06:55
  • ok, you are right. O(m) is 32 times faster however. – lo tolmencre Aug 16 '16 at 06:56
  • Regarding std::vector the reference says "These changes provide a quirky interface to this specialization and favor memory optimization over processing (which may or may not suit your needs)" And I need speed over low memory usage. – lo tolmencre Aug 16 '16 at 06:57
  • 1
    There is also [boost.dynamic_bitset](http://www.boost.org/doc/libs/1_61_0/libs/dynamic_bitset/dynamic_bitset.html) – stefaanv Aug 16 '16 at 07:01
  • Explanation about the 0x07, 3, 5: they belong to the `>> 3` example: 0x07 is 3 bits: 0b00000111, 3 is obvious, 5 is '8 - 3' because the example works on a container of bytes. – stefaanv Aug 16 '16 at 07:09
  • Ok, thanks. I would still like to know how to do the bitshifting of vectors thing on my own though :) I looked at the boost::synamic_bitset, but could not find the implementation of the operator<<. Edit: ninjaed – lo tolmencre Aug 16 '16 at 07:10
  • If you want to manipulate both ends of an array, `std::deque` might be a better choice than `std::vector`. If you allow the starting bit index to be dynamic instead of starting with full int, you can "shift" by manipulating the start and end index instead of manipulating the whole sequence of integers. – grek40 Aug 16 '16 at 08:53
  • I don't really understand. Can you elaborate on that? How would I set a starting bit index if the smallest units I can manipulate directly are bytes via chars? – lo tolmencre Aug 16 '16 at 09:00
  • 1
    @lotolmencre: "`O(m)` is 32 times faster" - no, it isn't. Big-O notation denotes a complexity class. There's exactly one linear complexity class, and it can't be faster than itself. – MSalters Aug 16 '16 at 09:39
  • 1
    [misleading comment about `std::deque`] removed. You should decide, whether 8 to 32 times memory consumption is a price you are ready to pay in order to have better speed. – grek40 Aug 16 '16 at 11:09

0 Answers0