私の友人はインタビューで次の質問をされました:「2進数を与えられて、最も重要なビットを見つけてください」。私はすぐに次の解決策を考えましたが、それが正しいかどうかはわかりません。
つまり、文字列を2つの部分に分割し、両方の部分を10進数に変換します。左側のサブ配列が10進数で0の場合、右側のサブ配列でバイナリ検索を行い、1を探します。
それは私の別の質問です。最上位ビット、2進数の左端の1ですか? 0が最も重要なビットである場合の例を、例と説明を添えて見せてください。
以下の回答には少し混乱があるようですので、質問をより正確にするために更新しています。インタビュアーは、「最上位ビットがデータの送信を停止することを示すまでデータを受信するWebサイトがあります」データ転送を停止するようにプログラムに指示するにはどうしますか?
ビットシフトを使用することもできます。疑似コード:
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はゼロです。
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];
}
ただし、実際には、より単純な方法(アンロールされたバイナリ検索など)は通常、同じかそれ以上に機能します。
これは、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
、それは無限ループなので、事前にゼロをテストします。
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) ); }
これは一種のトリックの質問だと思います。最上位ビットは常に1 :-)になります。面接官が側方思考を好む場合、その答えが勝者になるはずです!