两个左尖括号“<<”在C#中意味着什么?

时间:2010-03-22 15:32:46

标签: c# .net operators bitwise-operators bit-shift

基本上是标题中的问题。我正在看MVC 2的源代码:

[Flags]
public enum HttpVerbs {
    Get = 1 << 0,
    Post = 1 << 1,
    Put = 1 << 2,
    Delete = 1 << 3,
    Head = 1 << 4
}

我只是好奇双左角饼干<<的作用。

15 个答案:

答案 0 :(得分:131)

写作时

1 << n

您将位组000000001向左移n次,从而将n置于2的指数中:

2^n

所以

1 << 10

真的是

1024

对于说出5项的列表,您for将循环32次。

答案 1 :(得分:82)

它被称为left-shift运算符。看看documentation

  

左移运算符使第一个操作数中的位模式向左移位第二个操作数指定的位数。通过换档操作腾出的位是零填充的。这是一个逻辑移位而不是移位和旋转操作。

演示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

向左移动一位是两个等于两倍。事实上,移动位比标准乘法更快。让我们看一个证明这一事实的例子:

假设我们有两种方法:

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 :(得分:60)

那将是bitwise left shift运营商。

对于每个左移,该值实际上乘以2.因此,例如,写value << 3会将该值乘以8.

它内部真正的作用是将值的所有实际位移到一处。因此,如果您的值为12(十进制),则为二进制00001100;将它移到一个地方将把它变成00011000或24。

答案 3 :(得分:57)

它是Bitwise shift left它的工作原理是通过给定(右侧)数字移动数字的二进制等价数字。

这样:

temp = 14 << 2

二进制等效值为14 00001110将它移动2次意味着从右侧推零,并将每个数字移到左侧,使00111000等于56。

  

visual

在你的例子中:

i < (1 << list.Count)
    如果 list.Count = 0 0000000001 = 1 如果 list.Count = 1 0000000010 = 2 如果 list.Count = 2 0000000100 = 4 如果 list.Count = 3 0000001000 = 8

等等。一般来说它等于2 ^ list.Count(2提升到list.Count的力量)

答案 4 :(得分:36)

那是left bitshift运营商。它将左操作数的位模式向左移动右操作数中指定的二进制数字。

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)

答案 5 :(得分:23)

循环的目的很可能是生成或操作列表中项集的所有子集。并且循环体很可能也具有按位运算的良好位(har har),即另一个左移位和按位运算。 (所以重写它以使用Pow将是非常愚蠢的,我几乎不相信有那么多人实际建议。)

答案 6 :(得分:15)

多数转移。它基本上只是通过在右侧添加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

的更多信息

答案 7 :(得分:12)

除了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++)

等等。

答案 8 :(得分:9)

“向左移位。” 1 << 0表示“取整数值1并将其位向左移位”。即,00000001保持不变。 1 << 1表示“取整数值1并将其位移到一处。” 00000001变为00000010

答案 9 :(得分:8)

它的(&lt;&lt;)按位左移位运算符,它移动二进制对象的位值。左操作数指定要移位的值,右操作数指定值移位的位数。

在你的情况下,如果list.count的值是4,那么循环将运行直到i&lt; (1 <&lt; 4) 16 (00010000)

00000001&lt;&lt; 4 = 00010000(16)

答案 10 :(得分:7)

表达式(1 << N)在c#中使用Bit Shift

在这种情况下,它用于执行2 ^ N的快速整数计算,其中n为0到30.

年轻的whippersnappers 开发人员不熟悉位移的工作原理的好工具是程序员模式下的Windows Calc,可视化移位对各种大小的有符号数的影响。 LshRsh函数分别等同于<<>>

在循环条件中使用Math.Pow进行评估(在我的系统上)比N = 10的问题代码慢约7倍,这是否重要取决于上下文。

在单独的变量中缓存“循环计数”会稍微加快速度,因为涉及列表长度的表达式不需要在每次迭代时重新计算。

答案 11 :(得分:7)

隐含在许多答案中,但从未直接说明......

对于您左移二进制数的每个位置,您将该数字的原始值加倍。

例如,

小数5二进制左移一位是十进制10,或十进制5加倍。

小数5二进制左移3是十进制40,或十进制5加倍3次。

答案 12 :(得分:6)

以前的答案已经解释了它的作用,但似乎没有人对为什么进行猜测。我觉得这个代码的原因很可能就是循环遍历列表成员的每个可能组合 - 这是我可以看到为什么你想要迭代到2 ^ {list的唯一原因。计数}。因此,变量i将被严格命名:而不是索引(这是我通常将'i'解释为含义),它的位代表列表中项目的组合,因此(例如)第一项如果设置了i的位0((i & (1 << 0)) != 0),则可以选择;如果设置了位1((i & (1 << 1)) != 0),则可以选择第二项,依此类推。因此,1 << list.Count是第一个与列表中的有效项目组合不对应的整数,因为它表示选择了不存在的list[list.Count]

答案 13 :(得分:5)

我知道这个答案已经解决了,但我认为可视化可能有助于某人。

[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
}

答案 14 :(得分:0)

<<是左移位运算符。如果您有数字3(二进制为00000011),则可以编写3 << 2(即00001100)或十进制为12。