Java:マスクを使用してバイト配列から整数の分割ビットを抽出する方法を作成するにはどうすればよいですか
-
02-10-2019 - |
質問
いくつかのビデオストリーミング標準のデコードに取り組んでいる間、私は、整数値のビットが2〜6バイトのあらゆるもので提供されますが、予約されたビットで分離されている多くのインスタンスが次のように提供されています。
// Specification (16 bits)
// -----------------------
// Reserved 1 bit
// Value A [6-7] 2 bit
// Reserved 2 bit
// Value A [4-5] 2 bit
// Reserved 3 bit
// Value A [0-3] 4 bit
// Reserved 2 bit
たとえば、値185(10111001
また 0xB9
)2バイト配列に次のように保存されます。
01000110 00100100
私はこれがナッツであることを知っていますが、これはこれらの人たちが彼らのデータストリームをコーディングした方法です。次のビット操作を使用して抽出できます
int w = 0;
w |= (0x60 & data[0]) >>> 5; // extract the first 2 bits shifted to the front
w <<= 2; // bump them up 2 bits for the next section
w |= (0x06 & data[0]) >>> 1; // extract the next 2 bits shifted to the front
w <<= 4; // bump them up 4 bits for the last section
w |= (0x3C & data[0]) >>> 2; // extract the last 4 bits shifted to the front
// w now will equal 10111001 (185)
私ができることは、未定の長さのバイト配列と、提供された仕様から導出された値を抽出しようとしている値を構成するビットのマスクを表すINTを表すINTを受け入れる方法を作成することです。このようなもの
public static void testMethod() {
byte[] data = new byte[] {0x46, 0x24}; // 01000110 00100100
int mask = 0x663C; // 01100110 00111100
int x = readIntFromMaskedBytes(data, mask);
}
public static int readIntFromMaskedBytes(byte[] data, int mask) {
int result = 0;
// use the mask to extract the marks bits from each
// byte and shift them appropriately to form an int
return result;
}
元の「マニュアル」アプローチの使用に取り組んでいたプロジェクトを完了しましたが、これらの発生の数とその複雑さのために、それがきれいであることに満足していません。同じことを達成できるより一般的な方法を考え出したいと思います。
残念ながら、このビットシフトの複雑さに関しては、私はまだ初心者です。これを達成する最善の方法について誰かがアドバイスや提案を提供できることを望んでいました。
xela
注 - 上記の擬似コードの構文エラーは、ユースケースの説明として機能する設計のみです。
解決
実際、インラインマスクとシフトのアプローチ(擬似コードよりも少しきれいに実装されている場合)は、汎用的な方法を書こうとするよりも優れていると考える傾向があります。低レベルのビットバッシングコードの経験豊富な開発者の場合、マスクとシフトコードを読むことは問題ないはずです。提案しているラインに沿った汎用方法の問題は、それが大幅に効率が低くなり、JITコンパイラが最適化するのが難しいことです。
ところで、これが私がコードを書く方法です。
// extract and assemble xxxx from yyyy
int w = ((0x003C & data[0]) >> 2) |
((0x0600 & data[0]) >> 6) |
((0x6000 & data[0]) >> 7);
編集
学習演習として、このような一般的なアプローチがどのようにコーディングされるかをまだ理解したいと思います。
このようなもの:
public static int readIntFromMaskedBytes(int data, int mask) {
int result = 0;
int shift = 0;
while (mask != 0) {
if (mask & 1) {
result |= (data & 1) << shift++;
}
data >>>= 1;
mask >>>= 1;
}
}
ご覧のとおり、それはあなたに答えを与えるために最大32ループの反復が必要になります。あなたの例では、このアプローチは元のバージョンの約10倍遅いと思います。