views:

2786

answers:

5

I have an array of 128 booleans that represent bits. How can I convert these 128 bit representations into 16 bytes?

Example:

I have an array that looks like this:

0110001100110000100010111011001011010011010001010001101101001100
1000010000000000001000111111111101000011111001111011111011111001

(Converted to 1s and 0s to be more concise)

I need to convert those bits to the following byte array:

99 48 139 178 211 69 27 76 132 0 35 255 67 231 190 249

EDIT: This doesn't seem to work:

public byte[] ToByteArray() {
 int numBytes = Count / 8;

 if (_bits.Count % 8 != 0) numBytes++;

 byte[] bytes = new byte[numBytes];

 int byteIndex = 0, bitIndex = 0;

 for (int i = 0; i < _bits.Count; i++) {
  if (_bits[i])
   bytes[byteIndex] |= (byte)(1 << bitIndex);

  bitIndex++;
  if (bitIndex == 8) {
   bitIndex = 0;
   byteIndex++;
  }
 }

 return bytes;
}

It outputs:

198 12 209 77 203 162 216 50 33 0 196 255 194 231 125 159
+3  A: 

Check out this post.

dommer
I've edited my question with the results of that code, which doesn't appear to work for me.
David Brown
+1  A: 

I don't know if there's an automatic way to do it, but you can do it with a simple algorithm.

Simple algorithm:

  1. Create an array of bytes that will be used as your output buffer, and initialize all bytes to 0. The size of this array should be based on the length of your input boolean array: ceil(bool_array_length / 8.0)

  2. Declare an index variable to be used as your current byte, and set it to 0. This holds the index in your output buffer.

  3. Iterate over each element in your input boolean array.
    3.1. Left bit shift the number 1 by the array index mod 8. Call this number your mask.
    3.2. Calculate your byte index as your current index into the array div 8.
    3.3. If you have a boolean true value the current index in your input boolean array, do a bitwise OR with your current byte and your mask.

Brian R. Bondy
+4  A: 

The code is treating the first bit as the low bit of the word, so you end up with each word reversed. As a quick-and-dirty fix, try this:

bytes[byteIndex] |= (byte)(1 << (7-bitIndex));

That puts the first bit in the array at the highest position in the first byte, etc.

CAdaker
Awesome, thanks!
David Brown
A: 

Try this function (written as an extension method).

public byte[] ToByteArray(this bool[] bits)
{
    var bytes = new byte[bits.Length / 8];
    for (int i = 0, j = 0; j < bits.Length; i++, j += 8)
    {
        // Create byte from bits where LSB is read first.
        for (int offset = 0; offset < 8; offset++)
            bytes[i] |= (bits[j + offset] << offset);
    }

    return bytes;
}

Note: It will fail if the number of bits (bools) is not a multiple of 8, but judging by your question this isn't the case. It would only take a very small modificaiton to permit bit arrays of any length.

Noldorin
you meant "bytes[i] |= (bits[j + offset] << offset)" ?
Lucas
Yeah, of course. Well spotted.
Noldorin
+1  A: 
bool[] bools = ...
BitArray a = new BitArray(bools);
byte[] bytes = new byte[a.Length / 8];
a.CopyTo(bytes, 0);


EDIT: Actually this also returns:

198 12 209 77 203 162 216 50 33 0 196 255 194 231 125 159

Wrong endianness? I'll leave answer anyway, for reference.


EDIT: You can use BitArray.CopyTo() by reversing the arrays like so:

bool[] bools = ...
Array.Reverse(bools); // NOTE: this modifies your original array
BitArray a = new BitArray(bools);
byte[] bytes = new byte[a.Length / 8];
a.CopyTo(bytes, 0);
Array.Reverse(bytes);
Lucas