非常に興味深い質問であり、巧妙なトリックです。
シングルバイトを操作する簡単な例を見てみましょう。簡単にするために、符号なし8ビットを使用します。あなたの番号がxxaxxbxx
あなたが欲しいと想像してみてくださいab000000
。
このソリューションは、ビットマスキングとそれに続く乗算という2つのステップで構成されていました。ビットマスクは、興味のないビットをゼロに変換する単純なAND演算です。上記の場合、マスクは00100100
結果になり00a00b00
ます。
ここで難しいのは、それをに変えることab......
です。
乗算は、シフトおよび加算演算の集まりです。重要なのは、オーバーフローが不要なビットを「シフト」して、必要なビットを適切な場所に配置できるようにすることです。
4(00000100
)で乗算すると、すべてが2だけ左にシフトされ、次のようになりますa00b0000
。を上b
に移動するには、1(aを正しい位置に保つ)+ 4(bを上に移動する)を掛ける必要があります。この合計は5で、以前の4と組み合わせると、マジックナンバー20またはを取得し00010100
ます。オリジナルは00a00b00
マスキング後のものです。乗算は以下を与えます:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
このアプローチから、より大きな数とより多くのビットに拡張できます。
あなたが尋ねた質問の1つは、「これは任意のビット数で実行できますか?」でした。複数のマスキング操作または乗算を許可しない限り、答えは「いいえ」だと思います。問題は「衝突」の問題です。たとえば、上記の問題の「迷走b」などです。これをのような数にする必要があると想像してくださいxaxxbxxcx
。以前のアプローチに従って、{x 2、x {1 + 4 + 16}} = x 42が必要だと思うでしょう(ああ、すべてに対する答えです!)。結果:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
ご覧のとおり、それでも機能しますが、「ただ」だけです。ここで重要なのは、必要なビットの間に「十分なスペース」があり、すべてを絞り込めることです。cの直後に4番目のビットdを追加することはできませんでした。c+ dを取得するインスタンスが取得され、ビットが運ぶ可能性があるためです...
正式な証明がなければ、私はあなたの質問のより興味深い部分に次のように答えます:「いいえ、これはどのビット数でも機能しません。Nビットを抽出するには、目的のビットの間に(N-1)スペースが必要です抽出するか、追加のマスク乗算ステップを実行してください。」
「ビット間に(N-1)ゼロがなければならない」ルールについて私が考えることができる唯一の例外はこれです:オリジナルで互いに隣接している2つのビットを抽出し、かつそれらを同じ順序で、その後もそれを行うことができます。そして、(N-1)ルールの目的のために、それらは2ビットとしてカウントされます。
別の洞察があります-以下の@Ternaryの回答に触発されました(そこでの私のコメントを参照してください)。興味深いビットごとに、そこに行く必要があるビットのためのスペースが必要なだけ、その右側にゼロが必要です。ただし、左に結果ビットがあるのと同じだけ左にビットが必要です。したがって、ビットbがnの位置mで終了する場合、その左側にm-1個のゼロがあり、その右側にnm個のゼロがある必要があります。特に、ビットが元の番号と同じ順序になっていない場合は、並べ替え後のようになるため、これは元の基準に対する重要な改善です。これは、たとえば、16ビットワード
a...e.b...d..c..
にシフトすることができます
abcde...........
eとbの間にはスペースが1つしかなく、dとcの間には2つ、他のスペースの間には3つしかありません。N-1に何が起こった?? この場合は、a...e
「1ブロック」になります。1を掛けると、正しい場所に到着するので、「無料でeが手に入りました」。同じことがbとdにも当てはまります(bは右側に3つのスペースが必要で、dは左側に同じ3つのスペースが必要です)。したがって、マジックナンバーを計算すると、重複があることがわかります。
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
明らかに、これらの番号を別の順序で使用したい場合は、さらに間隔を空ける必要があります。(N-1)
ルールを再定式化できます。「ビット間に少なくとも(N-1)のスペースがある場合、または最終結果のビットの順序がわかっている場合、ビットbがmの位置に到達すると、常に機能します。 n、左にm-1個のゼロ、右にnm個のゼロが必要です。」
@Ternaryは、「ターゲット領域のすぐ右」にビットからキャリーが追加される可能性があるため、つまり、探しているビットがすべて1の場合、このルールはうまく機能しないことを指摘しました。上記の例を続けて、16ビットワードの5つの密にパックされたビットを使用します。
a...e.b...d..c..
簡単にするために、ビット位置に名前を付けます ABCDEFGHIJKLMNOP
私たちがやろうとしている数学は
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
これまでは、以下abcde
(positions ABCDE
)は問題ではないと考えていましたが、実際には、@ Ternaryが指摘したようb=1, c=1, d=1
に(b+c)
、その位置G
にあるとビットがposition F
に移動します。つまり(d+1)
、位置F
にあるビットがE
-結果は台無しです。c
乗算は最下位ビットのbeyoneからのゼロのパディングを引き起こすため、対象の最下位ビット(この例では)の右側のスペースは重要ではないことに注意してください。
したがって、(m-1)/(nm)ルールを変更する必要があります。「正確に(nm)未使用のビットが右側にある(上記の例では「c」であるパターンの最後のビットを数えない)複数のビットがある場合、ルールを強化する必要があります。繰り返します!
(nm)基準を満たすビット数だけでなく、(n-m + 1)などのビット数も調べる必要があります。それらの数をQ0(n-m
次のビットまで)、Q1( n-m + 1)、最大Q(N-1)(n-1)。次に、キャリーのリスクがあります
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
これを見てみると、簡単な数式を書けば
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
結果はW > 2 * N
であり、RHS基準を1ビットだけ増やす必要があります(n-m+1)
。この時点で、操作は安全W < 4
です。それでもうまくいかない場合は、基準をもう1つ増やします。
上記に従うことはあなたの答えへの長い道のりを得ると思います...