std::bitset 使い方のメモ

2020-03-24

たまに使おうとするとアレどうやるんだったっけってなるので使い方を雑にまとめておく。



はい

C++ リファレンス

概要

ビットの集合を表すクラス。便利な機能がついた、boolean の固定長配列のようなもの。

ビットを使った処理を整数型とビット演算だけでゴリっと書くよりもコードが直感的に読みやすくなる。

例えば、任意の整数値をビット列に変換したり、i番目のビットが立ってるかどうかの判定をしたり、ビットの合計をカウントしたりみたいなことが簡単にできる。

以下C++のバージョンは14で、任意のコード例は基本的に通称 575 こと using namespace std してる前提で書いていく。

ヘッダ

#include <bitset>

生成および初期化

ポイント🧐

まずテンプレート引数でサイズ(総ビット数)を指定する。

このとき指定したサイズは、動的に後から変更したりできないので注意。


コンストラクタ その1

総ビット数がNのbitsetを生成するコンストラクタ。この方法の場合最初は全ビット0になる。あんまり使ったことない。

bitset<N> bits;

コンストラクタ その2(重要)

任意の整数値を元にインスタンスを生成する。

下の例の場合、整数9から長さ5のビット列を生成する。

一番よく使う。というかほぼこれしか使ったことない。

bitset<5> bits(9); // 01001

コンストラクタ その3

二進数を表現した文字列を元にインスタンスを生成する。

下の例の場合、9を二進数で表現した文字列からbitsetを生成する。

bitset<5> bits("01001"); // 01001

文字列は二進数を表現したものでなければダメで、'0'または'1'以外の文字が含まれていた場合は例外がスローされる。

補足として、真を表す文字と偽を表す文字を受け取るコンストラクタもあって、それを使うと 0|1 以外の組み合わせの文字列からもインスタンス生成できる。(けど使ったことはない。)


入出力

cincout で入出力できる。(cout はちょっとデバッグしたりするときに地味に便利?)

cin で二進表記の文字列を入力、cout は二進表記の文字列を出力する。

int main() {
  bitset<5> bits;

  cin >> bits;
  cout << bits << endl;

  return 0;
}
1001    # 入力
01001   # 出力

なお、入力は二進表記でなければいけないので整数値を受け取ったりはできないことに注意。

9       # 入力(二進表記でないのでダメ)
00000   # 出力

アクセス(重要)

一番キモの部分。

bitseti ビット目にアクセスするには []演算子 を使う。

取得も設定もできる。

注意点として、ibitset のサイズを超えていても例外とか投げないので必ずサイズを超えないようにする必要がある。

int main() {
  bitset<5> bits(9); // 01001

  cout << bits[0] << endl; // 1
  cout << bits[1] << endl; // 0
  cout << bits[2] << endl; // 0
  cout << bits[3] << endl; // 1
  cout << bits[4] << endl; // 0

  bits[1] = 1;
  bits[2] = true;

  cout << bits[1] << endl; // 1
  cout << bits[2] << endl; // 1

  return 0;
}

整数型とビット演算で i ビット目が立ってるか確認する場合、if (bitmask >> i & 1) みたいな判定をしたりするけどこれが bitset なら if (bits[i])と簡潔にかける。わかりやすくてよい。😇

ちなみに test というメンバ関数がある。bits.test(i) みたいな感じで i ビット目を取得できる。

std::vector でいうところの at みたいなヤツ。

[]演算子との違いとしては、test のほうは範囲外を参照しようとしたときにちゃんと例外を投げてくれる。なのでこっちのほうが安全。

あと、set というメンバ関数もある。bits.set(i, true) または bits.set(i, false) のように、i ビット目のフラグをセットできる。test と同じように例外を投げてくれる。

だけど競プロとかではわざわざそこまでしなくてより短く書ける []演算子のほうを良く使う、、、と思う。


ビット演算

もろもろ演算子オーバーロードされていて、たいだいのことはできる。

&, |, ^, ~, &=, |=, ^= など。あとビットシフト <<, >>, <<=, >>= もちゃんとある。


お役立ちメンバ関数など

count(ちょっと重要)

立っているビットの合計をカウントしてくれるメンバ関数。

競プロでは、よく __builtin_popcount っていう gcc でしか使えないやつが使われているのを見るけどそれの bitset 版みたいな感じ。

flip

全ビットを反転するメンバ関数。

to_ullong

ビット列を unsigned long long 型に変換して返してくれるメンバ関数。

これの int 版とかはないっぽいので、手っ取り早く整数にしたかったらたぶんこれを使う事になると思う。

to_string

文字通り、ビット列を文字列に変換して返してくれるメンバ関数。

all

全ビットが1かどうかを判定するすメンバ関数。

any

一つ以上1なビットがあるかを判定するすメンバ関数。

none

全ビットが0かどうかを判定するすメンバ関数。



以上。より詳細はリファレンスを読みましょう。

オワリ😇

投稿一覧へ戻る