Working with a C++ data type on a bit by bit level

Started by
28 comments, last by DanBerliner 13 years ago

What about multi dimensional vectors? Would the same advantage apply to a multi dimensional vector? The math gets a little more annoying if it is one dimensional going over a two dimensional screen.



The simplest way to deal with multi-dimensional arrays is to use an underlying one-dimensional array and translate your multiple indices into a single index.

std::vector<bool> image(false, 1920*1080);
image[x+y*1080] = true;
Advertisement
int is 32 bits.
char is 8 bits.
short is 16.


Actually char is 8bit in 99% of all environments, and from there it's char < short <= int (not perfectly sure about about where it's < and <=). You will most likely find short to be 16bit most of the time and long to be 32bit, while int is the "natural" size for your platform (which happens to be 64bit if you compile for 64bit and 16bit for some old 16bit machines). Never make assumptions about the size of types, that's why there's a stdint header with all the int8_t typedefs (and a ton of #ifdefs).



[quote name='Nanoha']
unsigned int colour = 0;
colour |= (red << 24);
colour |= (green << 16);
colour |= (blue << 8);
colour |= |= alpha;
[/quote]

You realize that you can let the compiler do that kind of thing? (Including a somewhat silly use of union for interchangeable usage.


union
{
uint32_t color;
struct
{
uint32_t red : 8;
uint32_t green : 8;
uint32_t blue : 8;
uint32_t alpha : 8;
}
};


Though I honestly see little point in doing that over using using one uint8_t per channel in the first place.

While I would stick with vector<bool>, it wouldn't be that hard to use an array and get the bits yourself. Depending on the used type (unsigned int might be the most efficient), all you have to do is use your bit index and get the word and bit of that word ( i/sizeof(unsigned) and i%sizeof(unsigned) ). Somebody will point out that "it's teh fasta using bit fiddling", ie i>>4 and i&0xfffffff, but I haven't seen a compiler for a while that wasn't smart enough to turn / and % into bit operations for power of two operands.
f@dzhttp://festini.device-zero.de

Actually char is 8bit in 99% of all environments, and from there it's char < short <= int (not perfectly sure about about where it's < and <=).

In the current version of the C++ standard, it's char <= short <= int <= long with 8 <= char, 16 <= short, 32 <= long. It's perfectly possible for an implementation to have 32-bit everything (and at least one annoying embedded platform is that way).
I recall reading somewhere that bool was longer than 1 bit, after googling it again I see that I was incorrect. Thanks.[/quote]

sizeof(bool) is generally equal to sizeof(int), due to the fact that most platforms are unable to access individual bits and have alignment restrictions on other datatypes. However std::vector<bool> is specifically designed to pack the elements as tightly as possible, and incurs an instruction overhead in doing so. If you need to set a lot of bits at once and are worried about performance, you might want to avoid using the subscript operator.


sizeof(bool) is generally equal to sizeof(int), due to the fact that most platforms are unable to access individual bits and have alignment restrictions on other datatypes. [/quote]
I think you are mistaking the padded size of the variable with the sizeof(variable).

sizeof(bool) is normally equal to sizeof(char), which is defined as 1 and is most commonly 8 bits. However, the compiler padding will often mean that an individual boolean value is allocated a word of space by itself. However, contiguous booleans will be tightly packed by most compilers.

[quote name='Dan Berliner' timestamp='1302137979' post='4795293']
What about multi dimensional vectors? Would the same advantage apply to a multi dimensional vector? The math gets a little more annoying if it is one dimensional going over a two dimensional screen.



The simplest way to deal with multi-dimensional arrays is to use an underlying one-dimensional array and translate your multiple indices into a single index.

std::vector<bool> image(false, 1920*1080);
image[x+y*1080] = true;

[/quote]

I've done that, but just to iterate though an 800*600 (480,000) element vector takes my computer about 570-590ms. I have a pretty high end machine so that's unacceptably slow. It's just a simple iteration loop where it adds one to a int variable; the actual program will have to do significantly more than that per loop. When I was using an array of bool for the same sized screen it took about 47ms while drawing. Unless there is some way to optimize this considerably I dont see vectors as being a possible solution even if they can do the one bit thing.
Which compiler did you use for that benchmark? Some compilers create extra code even in release mode when using standard library templates. For example some versions of MSVC will enable _SECURE_SCL in release, which can significantly slow things down.

Which compiler did you use for that benchmark? Some compilers create extra code even in release mode when using standard library templates. For example some versions of MSVC will enable _SECURE_SCL in release, which can significantly slow things down.


I'm using MSVC, I'll look into optimizing on that compiler.
Would something like this work?




template <int SIZE_IN_BITS>
class BitArray
{
char bytes[SIZE_IN_BITS/8];

public:

BitArray()
{
memset(bytes,0,sizeof(bytes));
}

void SetBit(int bit)
{
int index = bit / 8;
int offset = bit % 8;

char mask = 1 << offset;

bytes[index] |= mask;
}

void ClearBit(int bit)
{
int index = bit / 8;
int offset = bit % 8;

char mask = 0xFF & ~(1 << offset);

bytes[index] &= mask;
}

bool GetBit(int bit)
{
int index = bit / 8;
int offset = bit % 8;

char mask = 1 << offset;

return (bytes[index] & mask) == mask;
}
};



EDIT: You probably want to make the internal array heap allocated if it's going to be large but the idea is the same...

I've done that, but just to iterate though an 800*600 (480,000) element vector takes my computer about 570-590ms.


Not saying it's the one and only reason, but if you want it to be FAST, you should go back to using int. Something that neatly fits the machines register size and doesn't require bitmasking and shifting for every access (though I'd expect no shifting and simply comparing with 0 after masking).

Keep in mind that the image you want to place your overlay on is apparently the same size and is also stored uncompressed as pixel data in memory, meaning it's also at least 24bit per pixel (unless it's scaled and your overlay has its own independent resolution). If storing is your issue, maybe you could use a simple compression like run length encoding (depending on how complex your overlays will get).
f@dzhttp://festini.device-zero.de

This topic is closed to new replies.

Advertisement