基本的にタイトルの質問。私はMVC2のソースコードを見ています:
[Flags]
public enum HttpVerbs {
Get = 1 << 0,
Post = 1 << 1,
Put = 1 << 2,
Delete = 1 << 3,
Head = 1 << 4
}
そして、私はダブルレフトアングルブラッカーが何をするのか興味<<
があります。
基本的にタイトルの質問。私はMVC2のソースコードを見ています:
[Flags]
public enum HttpVerbs {
Get = 1 << 0,
Post = 1 << 1,
Put = 1 << 2,
Delete = 1 << 3,
Head = 1 << 4
}
そして、私はダブルレフトアングルブラッカーが何をするのか興味<<
があります。
あなたが書くとき
1 << n
000000001
ビットの組み合わせをn
左にシフトし、n
2 の指数に入れます。
2^n
そう
1 << 10
本当にそうです
1024
たとえば 5 つの項目のリストの場合、for
32 回循環します。
オペレーターといいleft-shift
ます。ドキュメントを見てみましょう
左シフト演算子は、第 1 オペランドのビット パターンを、第 2 オペランドで指定されたビット数だけ左にシフトします。シフト操作によって空になったビットはゼロで埋められます。これは、シフトして回転する操作ではなく、論理シフトです。
left-shift
演算子を示す簡単な例:
for (int i = 0; i < 10; i++)
{
var shiftedValue = 1 << i;
Console.WriteLine(" 1 << {0} = {1} \t Binary: {2}",i,shiftedValue,Convert.ToString(shiftedValue,2).PadLeft(10,'0'));
}
//Output:
// 1 << 0 = 1 Binary: 0000000001
// 1 << 1 = 2 Binary: 0000000010
// 1 << 2 = 4 Binary: 0000000100
// 1 << 3 = 8 Binary: 0000001000
// 1 << 4 = 16 Binary: 0000010000
// 1 << 5 = 32 Binary: 0000100000
// 1 << 6 = 64 Binary: 0001000000
// 1 << 7 = 128 Binary: 0010000000
// 1 << 8 = 256 Binary: 0100000000
// 1 << 9 = 512 Binary: 1000000000
1 ビット左に移動することは、2 倍することと同じです。実際、ビットを移動することは、標準の乗算よりも高速です。この事実を示す例を見てみましょう。
2 つの方法があるとします。
static void ShiftBits(long number,int count)
{
long value = number;
for (int i = 0; i < count; i+=128)
{
for (int j = 1; j < 65; j++)
{
value = value << j;
}
for (int j = 1; j < 65; j++)
{
value = value >> j;
}
}
}
static void MultipleAndDivide(long number, int count)
{
long value = number;
for (int i = 0; i < count; i += 128)
{
for (int j = 1; j < 65; j++)
{
value = value * (2 * j);
}
for (int j = 1; j < 65; j++)
{
value = value / (2 * j);
}
}
}
そして、次のようにテストしたいと思います。
ShiftBits(1, 10000000);
ShiftBits(1, 100000000);
ShiftBits(1, 1000000000);
...
MultipleAndDivide(1, 10000000);
MultipleAndDivide(1, 100000000);
MultipleAndDivide(1, 1000000000);
...
結果は次のとおりです。
Bit manipulation 10.000.000 times: 58 milliseconds
Bit manipulation 100.000.000 times: 375 milliseconds
Bit manipulation 1.000.000.000 times: 4073 milliseconds
Multiplication and Division 10.000.000 times: 81 milliseconds
Multiplication and Division 100.000.000 times: 824 milliseconds
Multiplication and Division 1.000.000.000 times: 8224 milliseconds
それはビットごとの左シフト演算子になります。
左にシフトするたびに、値は事実上 2 倍になります。したがって、たとえば、書き込みvalue << 3
は値を 8 倍します。
内部で実際に行うことは、値の実際のビットをすべて 1 つの場所に移動することです。したがって、値が 12 (10 進数) の場合、2 進数では00001100
; 左に 1 桁ずらすと00011000
、または 24 になります。
それが左ビットシフト演算子です。左オペランドのビット パターンを、右オペランドで指定された 2 進数の数だけ左にシフトします。
Get = 1 << 0, // 1
Post = 1 << 1, // 2
Put = 1 << 2, // 4
Delete = 1 << 3, // 8
Head = 1 << 4 // 16
これは意味的にはlOperand * Math.Pow(2, rOperand)
ループの目的は、リスト内の項目セットのすべてのサブセットを生成または操作することです。また、ループ本体には、かなりのビット (har har) ビット演算、つまり別の左シフトとビット演算 and の両方が含まれている可能性が最も高いです。(したがって、Pow を使用するように書き直すのは非常にばかげているでしょう。実際にそれを提案した人がこれほど多くいたとは信じられません。)
それは少しシフトしています。基本的には、右側に 0 を追加してビットを左側に移動するだけです。
public enum HttpVerbs {
Get = 1 << 0, // 00000001 -> 00000001 = 1
Post = 1 << 1, // 00000001 -> 00000010 = 2
Put = 1 << 2, // 00000001 -> 00000100 = 4
Delete = 1 << 3, // 00000001 -> 00001000 = 8
Head = 1 << 4 // 00000001 -> 00010000 = 16
}
詳細については、http: //www.blackwasp.co.uk/CSharpShiftOperators.aspx をご覧ください。
Selman22の回答に加えて、いくつかの例:
list.Count
いくつかの値とループの内容をリストします。
list.Count == 0: for (int i = 0; i < 1; i++)
list.Count == 1: for (int i = 0; i < 2; i++)
list.Count == 2: for (int i = 0; i < 4; i++)
list.Count == 3: for (int i = 0; i < 8; i++)
などなど。
「左にビットシフト」 1 << 0
「整数値1を取り、そのビットをゼロビット左にシフトする」ことを意味します。つまり、00000001
変わらないままです。 1 << 1
「整数値 1 を取り、そのビットを 1 桁左にシフトする」ことを意味します。 00000001
になり00000010
ます。
その (<<) ビット単位の左シフト演算子で、バイナリ オブジェクトのビット値を移動します。左のオペランドはシフトする値を指定し、右のオペランドは値のビットをシフトする位置の数を指定します。
あなたの場合、list.count の値が 4 の場合、ループは i < (1<< 4)、つまり16 (00010000)まで実行されます。
00000001 << 4 = 00010000(16)
それは多くの回答で暗示されていますが、直接述べられることはありません...
2 進数を左にシフトする位置ごとに、数値の元の値が 2 倍になります。
例えば、
左に 1 シフトされた 10 進数 5 バイナリは 10 進数 10、または 10 進数 5 を 2 倍したものです。
3 だけ左にシフトされた 10 進数 5 バイナリは 10 進数 40、または 10 進数 5 を 3 回倍増したものです。
式(1 << N)
は、C# でビット シフトを使用します。
この場合、2^N の高速整数評価を実行するために使用されています。ここで、n は 0 から 30 です。
ための良いツール若いホイッパースナッパービット シフトがどのように機能するかを理解していない開発者は、さまざまなサイズの符号付き数値に対するシフトの効果を視覚化するプログラマ モードの Windows Calc です。Lsh
および関数は、それぞれ および とRsh
同等です。<<
>>
ループ条件内で Math.Pow を使用して評価すると、(私のシステムでは) N = 10 の質問コードよりも約 7 倍遅くなります。これが問題になるかどうかは、コンテキストによって異なります。
「ループカウント」を別の変数にキャッシュすると、リストの長さを含む式を反復ごとに再評価する必要がないため、わずかに速度が向上します。
以前の回答でそれが何をするのか説明されていますが、その理由について誰も推測していないようです。このコードの理由は、リストのメンバーの可能な組み合わせごとにループが繰り返されているためである可能性が非常に高いと思われます。これが、2^{list.カウント}。したがって、変数のi
名前は不適切です: インデックス (私が通常 'i' を意味すると解釈するもの) の代わりに、そのビットはリストの項目の組み合わせを表すため、(たとえば) ビットの場合、最初の項目が選択される可能性があります。ゼロi
が設定されている場合 ( (i & (1 << 0)) != 0
)、ビット 1 が設定されている場合は 2 番目の項目 ( (i & (1 << 1)) != 0
) などです。1 << list.Count
したがって、存在しない が選択されていることを示すため、 はリストの項目の有効な組み合わせに対応しない最初の整数ですlist[list.Count]
。
私はこの答えがほとんど解決されていることを知っていますが、視覚化が誰かを助けるかもしれないと思いました.
[Fact] public void Bit_shift_left()
{
Assert.Equal(Convert.ToInt32("0001", 2), 1 << 0); // 1
Assert.Equal(Convert.ToInt32("0010", 2), 1 << 1); // 2
Assert.Equal(Convert.ToInt32("0100", 2), 1 << 2); // 4
Assert.Equal(Convert.ToInt32("1000", 2), 1 << 3); // 8
}
<<
左ビットシフト演算子です。2 進数で 00000011 の 3 がある場合、3 << 2
00001100、または 10 進数で 12 と書くことができます。