C#中两个左括号“<<”是什么意思?

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

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

我只是好奇双左尖括号<<是什么。

这将是左移位运算符。

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

它在内部真正做的是把所有剩下的值的实际位移到一个地方。 所以如果你有值12(十进制),在二进制是00001100 ; 把它00011000一个地方就会变成00011000 ,即24。

当你写

 1 << n 

您将位组合000000001左移n次,从而将n指定为2的指数:

 2^n 

所以

 1 << 10 

真的是

 1024 

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

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

左移运算符使第一个操作数的位模式向左移位第二个操作数指定的位数。 换class操作腾空的位数为零。 这是一个合理的转变,而不是一个移位和旋转操作。

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

移动一位到左边是等于两乘。实际上,移动位比标准乘法更快。让我们来看看一个例子来certificate这个事实:

假设我们有两种方法:

 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); } } } 

我们要像这样testing它们:

 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 

这是按位左移它的工作原理是通过移动给定(右侧)数字的二进制等价数字的数字。

所以:

 temp = 14 << 2 

二进制等价的14是00001110将其移位2次意味着从右侧推零并将每个数位移到左侧,使得00111000等于56。

视觉

在你的例子中:

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

等等。 一般来说,它是等于2 ^ list.Count (2提高到list.Count的权力)

这是左移位运算符。 它将左操作数的位模式向右移动右操作数中指定的二进制数字的位数。

 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)

循环的目的很可能是在列表中的项目集的所有子集上生成或操作。 循环体最有可能还有一点点(哈哈)的按位操作,即另一个左移和逐位和。 (所以重写它来使用Pow将是非常愚蠢的,我不能相信有这么多的人实际上是这样build议的。)

这有点转变。 它基本上只是把位移到左边,在右边加上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并将其位左移0位”。 即, 00000001保持不变。 1 << 1表示“取整数值1并将其位移到一个位置”。 00000001变成00000010

它(<<)是一个按位左移运算符,它移动二进制对象的位值。 左边的操作数指定要移位的值,右边的操作数指定值中的位要移位的位置数。

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

00000001 << 4 = 00010000(16)

这是隐含在一些答案,但从来没有直接陈述…

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

例如,

十进制5的二进制向左移动一位是十进制10,或十进制5是一倍。

十进制5的二进制向左移3是十进制的40,或十进制的5的两倍3倍。

expression式(1 << N)在c#中使用位移 。

在这种情况下,它被用来执行2 ^ N的快速整数评估,其中n是0到30。

一个很好的工具 年轻whippersnappers 开发人员不知道位移是如何工作的,它是程序员模式下的Windows Calc,它可视化各种大小的带符号数的移位效应。 LshRsh函数分别等同于<<>>

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

将“循环计数”caching在一个单独的variables中会稍微加快一点,因为涉及列表长度的expression式不需要在每次迭代时重新计算。

以前的答案已经解释它的作用,但似乎没有人猜测为什么 。 我很可能认为这个代码的原因是循环遍历了列表成员的每个可能的组合 – 这是我能看到为什么要迭代到2 ^ {list的唯一原因。计数}。 因此,variablesi将被错误地命名为:而不是索引(这是我通常解释为'i'的意思),它的位表示来自列表的项目的组合,因此(例如)第一项可以被select如果(i & (1 << 0)) != 0 ),第二项如果第一位被设置( (i & (1 << 1)) != 0 )等等。 1 << list.Count因此是第一个不与列表中项目的有效组合相对应的整数,因为它将指示select不存在的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 }