web-dev-qa-db-ja.com

最上位ビットを見つけるアルゴリズム

私の友人はインタビューで次の質問をされました:「2進数を与えられて、最も重要なビットを見つけてください」。私はすぐに次の解決策を考えましたが、それが正しいかどうかはわかりません。

つまり、文字列を2つの部分に分割し、両方の部分を10進数に変換します。左側のサブ配列が10進数で0の場合、右側のサブ配列でバイナリ検索を行い、1を探します。

それは私の別の質問です。最上位ビット、2進数の左端の1ですか? 0が最も重要なビットである場合の例を、例と説明を添えて見せてください。

編集:

以下の回答には少し混乱があるようですので、質問をより正確にするために更新しています。インタビュアーは、「最上位ビットがデータの送信を停止することを示すまでデータを受信するWebサイトがあります」データ転送を停止するようにプログラムに指示するにはどうしますか?

11
user2398832

ビットシフトを使用することもできます。疑似コード:

number = gets
bitpos = 0
while number != 0
  bitpos++             # increment the bit position
  number = number >> 1 # shift the whole thing to the right once
end
puts bitpos

数値がゼロの場合、bitposはゼ​​ロです。

12

Cのような言語の命令のみを使用してWordの最上位ビットを見つける(つまり、切り捨てによるlog2の計算)は、De Bruijnシーケンスに基づくかなりよく知られた方法を使用して実行できます。たとえば、32ビット値の場合

unsigned ulog2(uint32_t v)
{ /* Evaluates [log2 v] */
  static const unsigned MUL_DE_BRUIJN_BIT[] = 
  {
     0,  9,  1, 10, 13, 21,  2, 29, 11, 14, 16, 18, 22, 25,  3, 30,
     8, 12, 20, 28, 15, 17, 24,  7, 19, 27, 23,  6, 26,  5,  4, 31
  };

  v |= v >> 1;
  v |= v >> 2;
  v |= v >> 4;
  v |= v >> 8;
  v |= v >> 16;

  return MUL_DE_BRUIJN_BIT[(v * 0x07C4ACDDu) >> 27];
}

ただし、実際には、より単純な方法(アンロールされたバイナリ検索など)は通常、同じかそれ以上に機能します。

9
AnT

これは、2つの補数の符号付き整数と32ビットを想定して、1つのアプローチです(ただし、特にプラットフォームに、最初の1つを数える、またはカウントをリードするゼロなどの単一命令ソリューションがある場合は、最も効率的ではありません)。整数の幅。

int mask = (int)(1U<<31); // signed integer with only bit 32 set
while (! n & mask)        // n is the int we're testing against
  mask >>= 1;             // take advantage of sign fill on right shift of negative number
mask = mask ^ (mask << 1) // isolate first bit that matched with n

最初のビットのビット位置が必要な場合は、31から始まり、各ループ反復で減少する整数カウンターを追加するだけです。

これの1つの欠点は、n == 0、それは無限ループなので、事前にゼロをテストします。

1
twalberg

C/C++ソリューションに興味がある場合は、本 "Matters Computational" byJörgArndt を参照してください。これらの関数は、「1.6.1最高のものを分離して見つけるそのインデックス」:

static inline ulong highest_one_idx(ulong x)
// Return index of highest bit set.
// Return 0 if no bit is set.
{
#if defined  BITS_USE_ASM
    return  asm_bsr(x);
#else  // BITS_USE_ASM

#if  BITS_PER_LONG == 64
#define MU0 0x5555555555555555UL  // MU0 == ((-1UL)/3UL) == ...01010101_2
#define MU1 0x3333333333333333UL  // MU1 == ((-1UL)/5UL)   == ...00110011_2
#define MU2 0x0f0f0f0f0f0f0f0fUL  // MU2 == ((-1UL)/17UL)  == ...00001111_2
#define MU3 0x00ff00ff00ff00ffUL  // MU3 == ((-1UL)/257UL)  == (8 ones)
#define MU4 0x0000ffff0000ffffUL  // MU4 == ((-1UL)/65537UL) == (16 ones)
#define MU5 0x00000000ffffffffUL  // MU5 == ((-1UL)/4294967297UL) == (32 ones)
#else
#define MU0 0x55555555UL  // MU0 == ((-1UL)/3UL) == ...01010101_2
#define MU1 0x33333333UL  // MU1 == ((-1UL)/5UL)   == ...00110011_2
#define MU2 0x0f0f0f0fUL  // MU2 == ((-1UL)/17UL)  == ...00001111_2
#define MU3 0x00ff00ffUL  // MU3 == ((-1UL)/257UL)  == (8 ones)
#define MU4 0x0000ffffUL  // MU4 == ((-1UL)/65537UL) == (16 ones)
#endif

    ulong r = (ulong)ld_neq(x, x & MU0)
        + ((ulong)ld_neq(x, x & MU1) << 1)
        + ((ulong)ld_neq(x, x & MU2) << 2)
        + ((ulong)ld_neq(x, x & MU3) << 3)
        + ((ulong)ld_neq(x, x & MU4) << 4);
#if  BITS_PER_LONG > 32
    r += ((ulong)ld_neq(x, x & MU5) << 5);
#endif
    return r;

#undef MU0
#undef MU1
#undef MU2
#undef MU3
#undef MU4
#undef MU5
#endif
}

asm_bsrは、プロセッサアーキテクチャに応じて実装されます

// i386
static inline ulong asm_bsr(ulong x)
// Bit Scan Reverse: return index of highest one.
{
    asm ("bsrl %0, %0" : "=r" (x) : "0" (x));
    return x;
}

または

// AMD64
static inline ulong asm_bsr(ulong x)
// Bit Scan Reverse
{
    asm ("bsrq %0, %0" : "=r" (x) : "0" (x));
    return x;
}

コードのためにここに行きます: http://jjj.de/bitwizardry/bitwizardrypage.html

編集:

これは、関数ld_neqのソースでの定義です。

static inline bool ld_neq(ulong x, ulong y)
// Return whether floor(log2(x))!=floor(log2(y))
{ return ( (x^y) > (x&y) ); }
0

これは一種のトリックの質問だと思います。最上位ビットは常に1 :-)になります。面接官が側方思考を好む場合、その答えが勝者になるはずです!

0
Stochastically