0

anのバイト表現 (つまり a byte[])を取得するのに、 int(4 バイトではなく) 3 バイトしか使用しない、読みやすい素敵な方法は何ですか? 私は Hadoop/Hbase を使用しており、そのBytesユーティリティ クラスにはtoBytes関数がありますが、常に 4 バイトを使用します。

理想的には、できるだけ少ないバイト数にエンコードする、すてきで読みやすい方法も必要です。つまり、数値が 1 バイトに収まる場合は 1 つだけを使用します。

これを に格納しているbyte[]ため、配列の長さはわかっているため、可変長エンコーディングは必要ありません。これは、キャストを行うエレガントな方法を見つけることです。

4

6 に答える 6

3

これに対する一般的な解決策は不可能です。

可能であれば、関数を繰り返し適用してデータを無制限に圧縮することができます。

ドメインによっては、整数を 24 ビットに圧縮できるという制約がいくつかある場合があります。そのような制約がある場合は、質問で説明してください。

一般的な可変サイズのエンコーディングでは、データに各バイトの 7 ビットを使用し、現在のバイトが最後であることを示すフラグとして上位ビットを使用します。


のユーティリティ メソッドを使用intして、をエンコードするのに必要なバイト数を予測できます。Integer

int n = 4 - Integer.numberOfLeadingZeros(x) / 8;
byte[] enc = new byte[n];
while (n-- > 0) 
  enc[n] = (byte) ((x >>> (n * 8)) & 0xFF);

これは、0 を空の配列としてエンコードし、その他の値をリトル エンディアン形式でエンコードすることに注意してください。これらの側面は、いくつかの操作を追加するだけで簡単に変更できます。

于 2012-07-06T23:56:05.737 に答える
1

2^32 個の既存の 4 バイト整数全体を表す必要がある場合は、次のいずれかを選択する必要があります。

  • 常に 4 バイトを使用する固定サイズの表現。また
  • 一部の数値に少なくとも 5 バイトを使用する可変サイズの表現。

UTF-8 が Unicode 文字をエンコードする方法を見てみましょう。いくつかの洞察が得られるかもしれません。(短いプレフィックスを使用して、その Unicode 文字を読み取る必要があるバイト数を記述し、そのバイト数を読み取って解釈します)。

于 2012-07-06T23:56:46.023 に答える
1

ByteBuffer を使用してみてください。必要に応じて、リトル エンディアン モードを設定することもできます。

int exampleInt = 0x11FFFFFF;
ByteBuffer buf = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
final byte[] threeByteBuffer = new byte[3];
buf.putInt(exampleInt);
buf.position(1);
buf.get(threeByteBuffer);

または、署名付きの最短のビッグ エンディアン:

BigInteger bi = BigInteger.valueOf(exampleInt);
final byte[] shortestSigned = bi.toByteArray();
于 2012-07-07T00:43:17.107 に答える
0

次のようなものから始めることができます。

byte[] Convert(int i)
{  // warning: untested
  if (i == 0)
    return new byte[0];
  if (i > 0 && i < 256)
    return new byte[]{(byte)i};
  if (i > 0 && i < 256 * 256)
    return new byte[]{(byte)i, (byte)(i >> 8)};
  if (i > 0 && i < 256 * 256 * 256)
    return new byte[]{(byte)i, (byte)(i >> 8), (byte)(i >> 16)};
  return new byte[]{(byte)i, (byte)(i >> 8), (byte)(i >> 16), (byte)(i >> 24)};
}

リトルエンディアンとビッグエンディアンのどちらになりたいかを決める必要があります。負の数は4バイトでエンコードされることに注意してください。

于 2012-07-07T00:25:32.323 に答える
0

intあなたを 4 bytes 配列に変換し、それを繰り返します。すべての上位バイトがゼロの場合は、配列から削除します。

何かのようなもの:

byte[] bytes = toBytes(myInt);
int neededBytes = 4;
for (;neededBytes > 1; i--) {
    if (bytes[neededBytes - 1] != 0) {
       break;
    }
}

byte[] result = new byte[neededBytes];
// then just use array copy to copy first neededBytes to result.
于 2012-07-06T23:58:11.333 に答える
0

難解なビットシャッフルを犠牲にしてでも、あなたが本当に、必死にスペースを節約したいと思っていることを私が正しく理解している場合:長さ=アドレス空間256に1バイト未満を使用できないため、配列タイプは不必要な贅沢です。ほとんどの 4 が必要になります。したがって、長さと符号フラグ用に 4 ビットを予約し、残りをそのバイト数に合わせて詰め込みます。MSB が 128 未満の場合は、さらに 1 バイト節約できます。符号フラグは、4 バイト未満で負の数を表す機能にも役立ちます。-1 を表すための 4 バイトのオーバーヘッドよりも、毎回 (正の数の場合でも) ビットを保持する方がよいでしょう。

とにかく、これはすべて、データセットに関する統計を作成し、実際に圧縮可能な整数の数と、圧縮のオーバーヘッドが努力する価値があるかどうかを確認するまでは、薄い水です。

于 2012-07-07T12:40:21.263 に答える