基本上,标题中所提出的问题。我正在查看MVC 2源代码:
[Flags]
public enum HttpVerbs {
Get = 1 << 0,
Post = 1 << 1,
Put = 1 << 2,
Delete = 1 << 3,
Head = 1 << 4
}
我只是好奇双左尖括号<<
有什么作用。
基本上,标题中所提出的问题。我正在查看MVC 2源代码:
[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的指数中:
您将比特组合 000000001
左移n
次,从而将n
放入2的指数中:
2^n
所以
1 << 10
真的是这样
1024
如果有一个包含5个项目的列表,那么您的for
循环将循环32次。
Math.Pow
计算循环次数就不再更有意义。这样你就不用担心让开发人员遇到转移混乱的问题了。 - GusdorMath.pow(n,2)
非常丑陋。例如,在Java中,这将涉及到从double进行转换。 - Ingovalue operator value
这种更易读的表示法)。说真的,你真的认为Convert.ToInt32(Math.Pow(2,value))
比1<<value
更易读了吗?现在操作符的含义已经被解释了。 - Jules它被称为 左移位
运算符。请查看文档
左移位运算符会使第一个操作数的比特模式向左移动由第二个操作数指定的比特位数。移位操作所空出的比特位将填充为零。这是一种逻辑移位,而不是移位和旋转操作。
下面是一个演示 左移位
运算符的简单例子:
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
将一个二进制位向左移动相当于乘以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。
它在内部实际上是将值的所有位向左移动一位。所以,如果你有值12(十进制),在二进制中,它是00001100
;向左移动一位将其变为00011000
,即24。
它是按位左移操作,通过将数字的二进制等效形式向右移动给定数量(在右侧)的数字位来实现。
因此:
temp = 14 << 2
14的二进制等价物是00001110
,将其向左移动两次意味着从右侧推入零并将每个数字向左移动,这使其等于00111000
,即56。
在你的例子中:
i < (1 << list.Count)
依此类推。一般地,结果等于2 ^ list.Count
(列表数量的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)
<< 33
与<< 1
是相同的。同样,在64位数学中,<< 65
与<< 1
是相同的。而右移又更加复杂,因为您需要考虑符号以知道要用什么填充。 - Marc Gravell循环的目的很可能是生成或操作列表中所有项目的所有子集。循环体很可能还涉及大量的位运算,即另一个左移和按位与。 (因此,重写为使用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
}
除了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,并将其位向左移动0位。”也就是说,00000001
保持不变。1 << 1
的意思是“取整数值1,并将其位向左移动一位。”00000001
变为00000010
。它(<<)是一个位左移运算符,它移动了二进制对象的位值。左操作数指定要移位的值,右操作数指定要移位的位数。
在您的情况下,如果list.count的值为4,则循环将运行直到i < (1<< 4),这是16(00010000)。
00000001 << 4 = 00010000(16)