2017-05-11 3 views
3

私の必要性である - uint32の一部(イン事実擬似)乱数を持って、私はそれは、1ビット目でものではない0、例えば述べる4最初のビットのニーズ=> 0000C#の

... 000100101 => 1001

1000年... 0001 => 1000年

... 0001 => 0001

... 0000

など このようなものを使用する必要があることを理解しています。

uint num = 1157 (some random number) 
uint high = num >> offset 

問題がある - 最初のビットは、私は一定の変数で>>を使用することはできませんここで私は知りません。どのようにこれを見つける方法を説明することができますoffset

+0

そのようなビットがあることは保証されていますか? '0000'や' 0010'の場合はどうなりますか? –

答えて

2

あなたが最初最上位ビット(HSB)を計算し、それに応じてシフトすることができます。

int hsb = -4; 
for(uint cnum = num; cnum != 0; cnum >>= 1, hsb++); 
if(hsb < 0) { 
    hsb = 0; 
} 
uint result = num >> hsb; 

このように、最初に最高のセットビット(またはそのインデックスからマイナス4)のインデックスを検出することを目指しています。何のセットビットはcnumにもはや存在しなくなるまで私たちは、hsbをインクリメントし、右にcnumnumのコピー)をシフトすることにより、これを行います。

次は、私たちは、このような一連のビットがあることを確認し、それが少なくとも指数4を持っていること(ない場合は、何も行われません)。その結果、オリジナルのnumは、hsbによって右にシフトされます。

私は0x123でこれを実行すると、私はcsharpインタラクティブシェルで0x9を得る:

csharp> uint num = 0x123; 
csharp> int hsb = -4; 
csharp> for(uint cnum = num; cnum != 0; cnum >>= 1, hsb++); 
csharp> if(hsb < 0) { 
     >  hsb = 0; 
     > } 
csharp> uint result = num >> hsb; 
csharp> result 
9 

0x123はバイナリで0001 0010 0011です。したがって:

0001 0010 0011 
    1 001

10019です。この回答へ

+1

ええ、これは正しいものでなければなりません。 – Bathsheba

1

私の以前の編集への根本的な欠点の一つは、エンディアンの配慮の欠如でした。この解決策は、(理論上)、あなたが作業しているアーキテクチャのために適切なビットシフトにコンパイラによって最適化されるべきです。最も重要な非ゼロのビットの位置を決定する

if(i == 0) 
    return 0; 

while(num < 128) 
    num *= 2; 

return num >> 28; 
+0

しかし、これは効果がありません。値を 'while'ループの左にシフトしたのと同じ場所にシフトします。 –

+0

うん。私は今答えを編集しています。それはちょうど28で簡単にシフトする必要があります。 –

+0

どこから28を得ましたか? whileループが何回実行されたかを数えてはいけませんか?そしてそれはnum << = 1であってはいけませんか? – vyrp

1

は、「ビットシフトのトリックは、」現代のCPU上ですぐにそれを行うにはありますベース2との対数を計算することと同じです。

int GetLog2Plus1(uint value) 
{ 
    value |= value >> 1; 
    value |= value >> 2; 
    value |= value >> 4; 
    value |= value >> 8; 
    value |= value >> 16; 
    value -= value >> 1 & 0x55555555; 
    value = (value >> 2 & 0x33333333) + (value & 0x33333333); 
    value = (value >> 4) + value & 0x0F0F0F0F; 
    value += value >> 8; 
    value += value >> 16; 
    value &= 0x0000003F; 
    return (int) value; 
} 

これは、0から32まで番号が返されます:。

 
Value          + Log2 + 1 
-------------------------------------------+--------- 
0b0000_0000_0000_0000_0000_0000_0000_0000U |  0 
0b0000_0000_0000_0000_0000_0000_0000_0001U |  1 
0b0000_0000_0000_0000_0000_0000_0000_0010U |  2 
0b0000_0000_0000_0000_0000_0000_0000_0011U |  2 
0b0000_0000_0000_0000_0000_0000_0000_0100U |  3 
... 
0b0111_1111_1111_1111_1111_1111_1111_1111U |  31 
0b1000_0000_0000_0000_0000_0000_0000_0000U |  32 
0b1000_0000_0000_0000_0000_0000_0000_0001U |  32 
...          | 
0b1111_1111_1111_1111_1111_1111_1111_1111U |  32 

(数学nitpickersが0の対数が未定義であることに気づくだろうしかし、私は、上記の表では、それが処理される方法を示して期待とこの問題には意味があります。)

値が8未満である場合は、その後、(どこLOG2 + 1が< 4)あなたは4つの最下位ビットを望ん考慮して、最も重要な非ゼロのビットを計算することができます。

var log2Plus1 = GetLog2Plus1(value); 
var bitsToShift = Math.Max(log2Plus1 - 4, 0); 
var upper4Bits = value >> bitsToShift;