バイト列からビット列を取り出す方法を考えます。
文法はすべてC#を使用します。
バイト列とは、たとえば
byte[] x = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A}; // 16進数表示
として得られる配列x。
このバイト列の、a バイト目の b ビット目(左から数える)を始点として、n ビット取り出すという問題を考えます。
配列xを2進数で表すと、
{ 00010010, 00110100, 01010110, 01111000, 10011010 }
となります。
a,bは、0から数えるルールにしますので、
たとえば a=1, b=3, n=4 のとき、以下の下線部が選択されます。
{ 00010010, 00110100, 01010110, 01111000, 10011010 }
ここでは、n<=16の場合のみを考えます。
ケース1
b+n <= 8 のとき
x[a]の中で完結します。
まず、x[a]のビット0(これは左端のビット)から、ビットb-1までをすべてゼロにします。
上の例では 00110100 → 00010100
これはand演算(&)を使って行います。
次に、8-(b+n) の数だけ、右にシフトします。論理シフト(左端は常にゼロを補填する)。
上の例では 00010100 → 8-(b+n) = 1ビットだけ右にシフト → 00001010
あとは、int型にでもキャストするなりして返してあげればよいです。
ケース2
8 < b+n <= 16のとき
例 a=1, b=5, n=9
{ 00010010, 00110100, 01010110, 01111000, 10011010 }
x[a]とx[a+1]のデータが必要になります。
x[a] = 00110100
x[a+1] = 01010110
x[a]からは、n1 = 8-b ビット (=3)の情報を
x[a+1]からは、n2 = n-n1 ビット (=6)の情報を 提供します。
まず、x[a]のビット0からビットb-1までをゼロにします(and演算)。そしてn2ビット(=6)だけ左シフトします。
x[a] : 00110100 →(and演算) &u(){00000}100 → (左シフト) → 100000000 (9桁表示)これをy[a]とします。
次に、x[a+1]を 8-n2 ビット (=2)だけ右シフトします。
x[a+1]: 01010110 → 00010101 これをy[a+1]とします。
最後に、y[a] | y[a+1]を計算
00000001 0000000 | 00000000 00010101 = 00000001 00010101
C#プログラムで記載するとこうです。
int n1 = 8 - b;
int n2 = n - n1;
int temp1 = (x[a] & mask[n1]) << n2;
int temp2 = (x[a + 1] >> (16 - b - n));
int result = temp1 | temp2;
なおmask配列の中身はこうです。
byte[] mask = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
ケース3
16 < b+n <= 24のとき
この場合は、3バイト分の情報から、上下をカットします。
C#プログラムを示します。
int n1 = 8 - b;
int n2 = 8;
int n3 = n - (n1 + n2);
int temp1 = (x[a] & mask[n1]) << (n2 + n3);
int temp2 = x[a + 1] << n3;
int temp3 = (x[a + 2] >> (24 - b - n));
int result = temp1 | temp2 | temp3;
最終更新:2012年03月14日 05:37