web-dev-qa-db-ja.com

ある位置以下でセットビットをカウントする効率的な方法は何ですか?

任意の数のビットが設定され、ビット位置がX(0-63)の_std::bitset<64> bits_を指定

X位置のビットが設定されていない場合に、X位置以下のビットをカウントする、または0を返す最も効率的な方法は何ですか

注:ビットが設定されている場合、戻り値は常に少なくとも1になります

力ずくの方法は非常に遅いです:

_int countupto(std::bitset<64> bits, int X)
{
  if (!bits[X]) return 0;
  int total=1;
  for (int i=0; i < X; ++i)
  {
    total+=bits[i];
  }
  return total;
}
_

bitsetcount() methofは、すべてのビットのpopcountを提供しますが、bitsetは範囲をサポートしていません

注:これは の重複ではありません32ビット整数の設定ビット数をカウントする方法 すべてのビットについて尋ねられるため0からXの範囲ではない

33

私の即座の反応は、指定されたビットをテストし、すぐにクリアの0を返すことです。

それを乗り越えた場合は、そのビット(および重要度の低いビット)が設定されたビットマスクを作成し、元の入力でandを作成します。次に、count()メンバー関数を使用して、結果に設定されているビット数を取得します。

マスクの作成に関しては、左に1桁シフトしてから、1を減算できます。

10
Jerry Coffin

_unsigned long_または_unsigned long long_が64ビットを保持するのに十分な大きさであると仮定すると、bits.to_unlong()(またはbits.to_ullong())を呼び出して、ビットセットデータを整数として取得できます。 X(_(1 << X) - 1_)より上のビットをマスクして、リンク先の質問への回答に示されているビットをカウントします。

5

ビットとその下のビットのマスクの間で変換するのは簡単なので、次のようなものが機能するはずです。

int popcnt(bitset<64> bs, int x) {
    // Early out when bit not set
    if (!bs[x]) return 0;
    // Otherwise, make mask from `x`, mask and count bits
    return (bs & bitset<64>((1UL << x) - 1)).count() + 1;
}

ここでの前提は、bitset::countは効率的に実装されています(popcnt組み込み関数または効率的なフォールバックを使用)。これは保証されていませんが、STLスタッフはこの種のものを最適化する傾向があります。

5
ShadowRanger

以前見た問題を編集して、奇数または偶数のビットが設定されているかどうかを確認しました。これはC用ですが、C++にマッサージするのはそれほど難しくないはずです。ソリューションの核心は、whileループにあるものです。紙で試して、LSBを選択してxから削除する方法を理解してください。コードの残りの部分は簡単です。コードはO(n)で実行されます。nはxの設定ビット数です。これは、この問題を最初に見たときにのみ可能だと私が考えていた線形時間よりもはるかに優れています。

#include <stdio.h>

int
count(long x, int pos)
{
    /* if bit at location pos is not set, return 0 */
    if (!((x >> pos) & 1))
    {
        return 0;
    }

    /* prepare x by removing set bits after position pos */
    long tmp = x;
    tmp = tmp >> (pos + 1);
    tmp = tmp << (pos + 1);
    x ^= tmp;

    /* increment count every time the first set bit of x is removed (from the right) */
    int y;
    int count = 0;
    while (x != 0)
    {
        y = x & ~(x - 1);
        x ^= y;
        count++;
    }
    return count;
}

int
main(void)
{
    /* run tests */
    long num = 0b1010111;
    printf("%d\n", count(num, 0)); /* prints: 1 */
    printf("%d\n", count(num, 1)); /* prints: 2 */
    printf("%d\n", count(num, 2)); /* prints: 3 */
    printf("%d\n", count(num, 3)); /* prints: 0 */
    printf("%d\n", count(num, 4)); /* prints: 4 */
    printf("%d\n", count(num, 5)); /* prints: 0 */
    printf("%d\n", count(num, 6)); /* prints: 5 */
}
1
nobism