1
\$\begingroup\$

The way I am using this method assumes all data is byte-aligned, so I don't really care about the rest of the bits.

This method is written in an extension of BinaryReader which provides more methods when I'm reading binary data from files. The BinaryReader provided does not appear to support reading bits.

Is there a better way I could write this method? Also I'm not sure if there's a more direct way to build a bitmask so I did it the long way.

/* Returns the value of the first n bits. */
public byte ReadBits(byte n)
{
    byte val = base.ReadByte();
    byte sum = 0;
    for (int i = 0; i < n; i++)
        sum += (byte)(val & (1 << i));
    return sum;
}

I am using .NET 3.5

\$\endgroup\$
4
  • \$\begingroup\$ I don't think so. For example you read 4 bits and it tells the length of the following data. I'd want it as an int or a byte. \$\endgroup\$
    – MxLDevs
    Aug 15, 2012 at 22:30
  • \$\begingroup\$ It is similar to ReadInt32 or ReadByte: just return a single value that is represented by the bytes that were read. Or in this case, bits. I have not thought about the case where there is no byte alignment, but adobe's SWF format is always byte-aligned. \$\endgroup\$
    – MxLDevs
    Aug 15, 2012 at 22:55
  • \$\begingroup\$ Oh, I should probably mention that this particular method is written in an extension of BinaryReader, which is why it explicitly reads bytes as the first line rather than taking a stream of bytes. \$\endgroup\$
    – MxLDevs
    Aug 15, 2012 at 23:00
  • \$\begingroup\$ That would be an appropriate method for the BitConverter, where it takes some input and returns a converted value. However I think since I just need to read n bits and ignore the rest, it would be fastest to just do the operation in one call rather than making the extra conversion afterwards. \$\endgroup\$
    – MxLDevs
    Aug 15, 2012 at 23:15

1 Answer 1

3
\$\begingroup\$

I have not tested this that well. If anyone finds a bug, please let me know.

// Throws away the unused bits
public byte ReadFirstNBits(int n)
{
    Contract.Requires(n >= 0 && n <= 8, "Code contract may be too slow for your needs");
    byte val = base.ReadByte();
    return val >> (8 - n);
}

// Throws away the unused bits
public byte ReadLastNBits(int n)
{
    Contract.Requires(n >= 0 && n <= 8, "Code contract may be too slow for your needs");
    byte val = base.ReadByte();
    byte mask = (byte)((1 << n) - 1);
    return val & mask;
}

You can try this for yourself if you have a Python prompt:

>>> a = 0b11001001 
>>> a
201
>>> a >> 4
12
>>> a >> 5
6
>>> a >> 3
25
>>> a >> 6
3
>>> a >> 2
>>> for i in range(8): print bin(a >> i)

0b11001001
0b1100100
0b110010
0b11001
0b1100
0b110
0b11
0b1
>>> 
\$\endgroup\$
4
  • \$\begingroup\$ Bit-shifting has always been a mystery to me. I was reading this stackoverflow.com/a/141873/536607 and it sort of gives me a better idea and can understand why shifting would work for this problem. Hopefully it will come to mind immediately when working with bit operations. \$\endgroup\$
    – MxLDevs
    Aug 15, 2012 at 23:31
  • \$\begingroup\$ Well, I am glad this was helpful. \$\endgroup\$
    – Leonid
    Aug 16, 2012 at 15:57
  • \$\begingroup\$ >= 0 && <= 8 shouldn't it be >= 0 && < 8? \$\endgroup\$
    – luiscubal
    Aug 16, 2012 at 16:23
  • \$\begingroup\$ @luiscubal, you could chose to read the entire byte, which is 8 bits long, in which case val >> 0 should just give you val. It is not as fast as simply calling base.ReadByte(), but it works correctly. The number of bits to read could be stored in a variable. I find the case where you wish to read 0 bits more ridiculous, but ... the computers do not necessarily do what you meant; only what you told them. \$\endgroup\$
    – Leonid
    Aug 16, 2012 at 16:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.