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
-
\$\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– MxLDevs2012年08月15日 22:30:40 +00:00Commented 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– MxLDevs2012年08月15日 22:55:04 +00:00Commented 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– MxLDevs2012年08月15日 23:00:19 +00:00Commented 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– MxLDevs2012年08月15日 23:15:57 +00:00Commented Aug 15, 2012 at 23:15
1 Answer 1
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
>>>
-
\$\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– MxLDevs2012年08月15日 23:31:49 +00:00Commented Aug 15, 2012 at 23:31
-
\$\begingroup\$ Well, I am glad this was helpful. \$\endgroup\$Leonid– Leonid2012年08月16日 15:57:28 +00:00Commented Aug 16, 2012 at 15:57
-
\$\begingroup\$
>= 0 && <= 8
shouldn't it be>= 0 && < 8
? \$\endgroup\$luiscubal– luiscubal2012年08月16日 16:23:25 +00:00Commented 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 youval
. It is not as fast as simply callingbase.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 read0
bits more ridiculous, but ... the computers do not necessarily do what you meant; only what you told them. \$\endgroup\$Leonid– Leonid2012年08月16日 16:55:53 +00:00Commented Aug 16, 2012 at 16:55