bit列で数値を抜き出す必要性
一部のプロトコルではデータがbyteやinteger単位ではなく、bit単位で設定されています。
特定bit列を数値に変換するには先頭bitから最終bitまでシフトしつつ足していくことで取得することができますが、バイト単位にキャストしたほうが早いように思うので試してみます。
バイト単位にキャストしたサンプルコード
public long bitToLong1(final byte[] data, int startBit, int length) { int firstByte = startBit / 8; int firstByteStartBit = startBit % 8; int firstByteLength = length + firstByteStartBit > 8 ? 8 - firstByteStartBit : length; int firstByteSpareBit = 8 - (firstByteStartBit + firstByteLength); // 1バイトで終了するケース if(firstByteLength >= length) return (data[firstByte] >>> firstByteSpareBit) & (0xff >>> (8 - firstByteLength)); // 先頭バイトキャスト long sum = data[firstByte] & (0xff >>> (8 - firstByteLength)); // 2バイト目から8bitすべて含むバイトをキャスト int numberOfFullByte = (length - firstByteLength) / 8; int count; for(count = 1; count <= numberOfFullByte; count++) { sum = (sum << 8) + (data[firstByte + count] & 0xff); } // 最後に8ビットに満たないバイトがない場合 int lastByteLength = length - (firstByteLength + numberOfFullByte * 8); if(lastByteLength == 0) return sum; // 最後の8ビット未満のバイトをキャスト return (sum << lastByteLength) + ((data[firstByte + count] & 0xff) >>> (8 - lastByteLength)); }
ByteBufferを使用したサンプルコード
public long bitToLong2(byte[] data, int startBit, int length) { int firstByte = startBit / 8; int firstByteStartBit = startBit % 8; // 抽出するビットを含むバイト列をコピー byte[] dst = new byte[8]; System.arraycopy(data, firstByte, dst, 0, (startBit + length + 7) / 8 - firstByte); //先頭バイトを先頭ビットまで0でマスク dst[0] &= 0xff >>> firstByteStartBit; // BytBufferでlongに変換 long sum = ByteBuffer.wrap(dst).getLong(); // 後ろの余分なビット分シフト sum >>>= 64 - (startBit + length) + firstByte * 8; return sum; }
処理能力
7バイトのバイト配列を等差数列的に総なめする動作を100,000回ループさせた結果は次のとおりでした(単位はmsec)。
1回目 | 2回目 | 3回目 | |
---|---|---|---|
bitToLong1 | 1122 | 1172 | 1109 |
bitToLong2 | 2269 | 2251 | 2253 |
bit単位のループ | 8464 | 8530 | 8495 |
まとめ
ByteBufferのソースコードを確認すると最終的にはキャストしていたので性能としてあまり差はでないはずです。 処理速度を求めない人には可読性を重視したほうがよいかもしれません。