多くのブール状態を1つの数値に格納/パックするための名前は何ですか?


55

これは、1つの数値変数を使用して多くのブール値/バイナリ状態を格納する単純な圧縮の一種です。倍増と、倍増数はすべて1 +前のすべての合計であるという事実を使用します。

私はそれが古い、よく知られたテクニックでなければならないと確信しています、私はそれを適切に参照するために何と呼ばれるか知りたいです。私はそれを説明するために考えられるあらゆる方法でいくつかの検索を行いましたが、記事の著者が自分でこれを理解していると思われるいくつかのブログ記事以外には何も見つかりませんでした(例1例2)。

たとえば、概念を説明するための非常に単純な実装を次に示します。

packStatesIntoNumber () {
  let num = 0
  if (this.stateA) num += 1
  if (this.stateB) num += 2
  if (this.stateC) num += 4
  if (this.stateD) num += 8
  if (this.stateE) num += 16
  if (this.stateF) num += 32
  return num
}

unpackStatesFromNumber (num) {
  assert(num < 64)
  this.stateF = num >= 32; if (this.stateF) num -= 32
  this.stateE = num >= 16; if (this.stateE) num -= 16
  this.stateD = num >= 8; if (this.stateD) num -= 8
  this.stateC = num >= 4; if (this.stateC) num -= 4
  this.stateB = num >= 2; if (this.stateB) num -= 2
  this.stateA = num >= 1; if (this.stateA) num -= 1
}

ビット単位の演算子、基数2の数値解析、列挙型を使用することもできます。それを実装するより多くの効率的な方法があります。より一般的なアプローチの名前に興味があります。


8
C#にはenumsがあり、Flags属性を持つことができます。彼らはあなたのコードをはるかに簡単にすることができます。
ベルンハルトヒラー

12
これを「ビットフィールドのシミュレーション」と呼びます。スペース効率が圧倒的に重要でない限り、ほとんど常に悪い考えです。
キリアンフォス

7
@KilianFoth A boolは通常、内部的に32ビット整数として保存されます。そのため、パッキングによって32倍の差が生じる可能性があります。それは本当に大きなことです。つまり、私たちプログラマーは常に私たちのリソースの半分を捨てる用意ができていますが、私は一般的にそれらの97%を捨てることに消極的です。このような無駄な要素は、重要なユースケースを実行できるかどうかと、メモリが不足するかどうかを簡単に区別できます。
cmaster

3
歴史的に、ビットマスクを使用して値を宣言、設定、取得する一般的な方法。シフトの使用は奇妙であり、実際にはアプローチの最良の例ではありません。
ジミージェームズ

3
@cmaster boolsがそのように格納される理由は、単一のメモリ位置(今日のマシンでは32ビットまたは64ビット)を共有することは、マシン言語コードに多くの注意を払わない限り、キャッシュパフォーマンスにとって非常に悪いためです。本当に大量のビットがある場合はおそらく価値がありますが、そうでない場合は、ネットワークまたはディスクに送信する準備ができているときに事前に最適化せずにビットをパックする方が良いでしょう。
ビルK

回答:


107

最も一般的にビットフィールドと呼ばれ、よく耳にする別の用語はビットマスクです。これは、個々のビット値またはビットフィールド全体を一度に取得または設定するために使用されます。

多くのプログラミング言語には、これを支援する補助構造があります。@BernhardHillerがコメントで述べているように、C#にはフラグ付きの列挙型があります。JavaにはEnumSetクラスがあります。


4
「ビットフィールド」は、ビット単位の演算子を使用して手動で行うのではなく、個々のビットを構造体のフィールドに割り当てることができる言語機能を使用していると解釈します。
ピーターグリーン

22
@PeterGreenこれは、標準の解釈とは異なります。
エリック

1
「ビットマッピング」または「ビットマッピング」は、レコードセットおよび配列処理に共通ですが、この場合にも適用できます。複数のセットから共通の要素を抽出する場合、値を分解して連合モデルのコンポーネントを識別することができます。これを8進数のファイルモードの数字で言うこともあります。ビットマスク(任意のマスク)は、フィルターである傾向があります(IOポートおよびデータ方向レジスターに関して)。
mckenzm

1
C#にはがありBitArray、これにより、任意の量のビットを格納してインデックスを作成できます(フラグは整数型に制限され、マスクとして使用することを目的としています)。
ルアーン

本当; 私が最もよく知っている2つの構造について言及しました。特に他の言語では、おそらく数十個あります。
グローフィンデル

20

奇妙な、かなり異なる用語がここにありますが、すぐに思い浮かぶものはありません(そして、それはあなたの質問のタイトルにあります!)-ビットパッキングは、私がいつもそれを命名したと聞いたものです。

これは本当に明白だと思っていましたが、グーグルで検索すると、これは広く使用されているが公式に定義されていない用語のようです(ウィキペディアはビットパッキングを行う方法であるビットフィールドにリダイレクトするようですが、処理する)。定義を検索すると、このページにつながるようです:

http://www.kinematicsoup.com/news/2016/9/6/data-compression-bit-packing-101

これはSOの目的には適していませんが、この簡潔な説明を含めて見つけることができる最高の定義/説明です。


参考資料を提供できますか?興味深い用語。
グレッグブルクハート

13
ビットパッキングは技術的には正しいものですが、ブール型の状態よりも一般的なことも指します。一般的には、できるだけ少ないビット数でデータを保存します。たとえば、もう1つの使用法は、char2つcharのsをoneに入れて配列を圧縮することを意味しintます。
イズカタ

@GregBurghardtあなたは知っている、それは面白いです。Cやアセンブリでプログラミングを学んだ80年代/ 90年代にこの用語が流行していたため、投稿したときは考えていませんでした-今ではGoogle検索で多くの言及が見つかりましたが、Wikipediaの決定的なページはありません。グーグルの最初の答えはこの定義を持っています:「ビットパッキングは単純な概念です:データの一部を保存するためにできるだけ少ないビットを使用してください。」kinematicsoup.com/news/2016/9/6/...
ビル・K

それはビットパッキングについても学んだときですが、名目上整数値である未使用の0を単純に再利用するよりもはるかにクレイジーになります。数年前、私はそのパラメーターの1つを8ビットの浮動小数点数として保管するシステムに遭遇しました。符号なし仮数の場合はIIRC 5ビット(すべての値は正であり、明示的に符号を保存する必要はありません)、さらに10を底とする指数の場合は3ビット。私はそれが先に進まないレガシーハードウェアクラッジだと思っていましたが、最近機械学習がint4対int8で何かを始めたので、FP16からいくつかのワークロードが落ちるのを見ることができました。
ダン・ニーリー

1
@DanNeelyこの種のことは、GPUでも一般的にサポートされています。そこでは、精度、メモリ、計算の間のトレードが非常に重要です。これはGPUベースのコンピューティングでもかなりうまく利用されています。
ルアーン

14

これを説明するために使用される多くの異なる用語があります。

最も一般的なビットは、「ビットフラグ」または「ビットフィールド」と呼ばれます。
(ただし、「ビットフィールド」とは、C言語およびC ++言語の特定の機能を指す場合があり、それらは関連しているがまったく同じではないことに注意してください。)

整数自体は、用途と状況に応じて、「ビット配列」、「ビットセット」、または「ビットベクトル」と呼ばれます。

いずれにせよ、ビットセット/ベクトル/配列からのビットの抽出は、シフトとマスキングによって行われます。
(つまり、ビットマスクを使用します。)


積極的に使用されている各用語の例:

  • このテーマに関するウィキペディアの記事は、「ビット配列」というタイトルで、「ビットマップ、ビットセット、ビット文字列、またはビットベクトル」とも呼ばれています。
  • C ++の使用 std::bitset
  • Javaが使用する BitSet
  • C#の使用 BitArray
  • StackOverflowにはタグbitvectorbitarrayあり、bitset
  • PyPiにはbitarrayプロジェクトとプロジェクトがありBitVectorます

質問にはあまり関係ありませんが、言いたいのは、ビットの設定とクリアに加算と減算を使用しないでください。これらの方法はエラーを起こしやすいためです。
(つまり、num += 12回実行すると、結果はに等しくなりnum += 2ます。)

選択した言語が提供する場合は、代わりに適切なビット演算を使用することをお勧めします。

packStatesIntoNumber ()
{
  let num = 0
  if (this.stateA) num |= 1
  if (this.stateB) num |= 2
  if (this.stateC) num |= 4
  if (this.stateD) num |= 8
  if (this.stateE) num |= 16
  if (this.stateF) num |= 32
  return num
}

unpackStatesFromNumber (num)
{
  this.stateF = ((num & 32) != 0);
  this.stateE = ((num & 16) != 0);
  this.stateD = ((num & 8) != 0);
  this.stateC = ((num & 4) != 0);
  this.stateB = ((num & 2) != 0);
  this.stateA = ((num & 1) != 0);
}

1
this.stateF = (num & 32) ? true : false、などnum。値を抽出している間は変更する必要はありません。
ロジャーリップスコム

3
@RogerLipscombe良い点は、コードの実行内容を実際に読んでおらず、+and の使用に反応するだけでした-。私は今、1つをより良くして!= 0、3項の代わりに使用しました。
ファラプ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.