2の累乗かチェックする方法

古典的なビットトリック:n & (n - 1) == 0。なぜ動作するか、エッジケース、メモリ割り当てやハッシュテーブルでの実用的な応用を学びます。

Bit Tricks

詳細な説明

2の累乗チェック

正の整数がバイナリ表現でちょうど1つのビットが設定されている場合のみ、2の累乗です。古典的なワンライナーテスト:

function isPowerOf2(n) {
  return n > 0 && (n & (n - 1)) === 0;
}

なぜ動作するか

2の累乗のバイナリは、1つの1の後にゼロが続く形:

  1   = 00000001
  2   = 00000010
  4   = 00000100
  8   = 00001000
 16   = 00010000

1を引くと最下位の設定ビットとそれ以下のすべてのビットが反転:

  8     = 00001000
  8 - 1 = 00000111

ANDすると、重複がないため2の累乗では常にゼロ:

  00001000
& 00000111
──────────
  00000000

2の累乗でない場合、少なくとも1つの上位ビットが残る:

  6     = 00000110
  6 - 1 = 00000101
  6 & 5 = 00000100  (ゼロではない!)

エッジケース

  • n = 0: falseを返す。0は2の累乗ではなく、n > 0チェックで処理。
  • n < 0: falseを返す。負の数は2の累乗ではない。
  • n = 1: trueを返す。2^0 = 1。

関連トリック:次の2の累乗

次の2の累乗に切り上げる:

function nextPowerOf2(n) {
  n--;
  n |= n >> 1;
  n |= n >> 2;
  n |= n >> 4;
  n |= n >> 8;
  n |= n >> 16;
  return n + 1;
}

最上位の設定ビットを下方に伝播させ、すべての下位ビットを1で埋め、1を足します。

ユースケース

jemallocやdlmallocなどのメモリアロケータは、割り当てサイズをビンに分類するために2の累乗チェックを使用します。要求サイズがすでに2の累乗ならサイズクラスに直接マッピングされ、そうでなければアライメントのため次の2の累乗に切り上げられます。ハッシュテーブルも2の累乗サイズを必要とし、モジュロ演算を高速なANDマスク(index = hash & (size - 1))で置き換えます。

試してみる — Bitwise Calculator

フルツールを開く