web-dev-qa-db-ja.com

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

これは一種の単純な圧縮であり、1つの数値変数を使用して多数のブール/バイナリ状態を格納します。これは、2倍算を使用し、すべての2倍数は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の数値解析、列挙型を使用することもできます。これを実装するには、より多くの効率的な方法があります。より一般的なアプローチの名前に興味があります。

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

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

106
Glorfindel

奇妙なことに、ここにはかなり異なる用語がたくさんありますが、すぐに頭に浮かんだ用語は見当たりません(そして、それはあなたの質問のタイトルにあります)。

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

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

これはSOの目的には適していませんが、この簡潔な説明を含めて、私が見つけることができる最良の定義/説明です。「ビットパッキングは単純な概念です。データの一部。」

20
Bill K

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

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

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

どちらの方法でも、ビットセット/ベクトル/配列からビットを抽出するには、シフトとマスキングを行います。
(つまり、 ビットマスク を使用します。)


活発に使用されている各用語のいくつかの例については:

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

それは質問にはあまり関係ありませんが、私は言いたいのですが、ビットを設定およびクリアするために加算および減算を使用しないでください。これらの方法はエラーが発生しやすいためです。
(つまり、num += 1を2回実行すると、結果は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);
}
14
Pharap