繁体   English   中英

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

[英]What do two left-angle brackets “<<” mean in C#?

基本上是标题中的问题。 我正在查看 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 的指数中:

2^n

所以

1 << 10

真的是

1024

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

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

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

演示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。因此,例如,写入value << 3会将值乘以 8。

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

它是按位左移,它通过将数字的二进制等效数字移位给定(右侧)数字来工作。

所以:

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)

循环的目的最有可能生成或操作列表中项目集的所有子集。 并且循环体很可能还有一个很好的位 (har har) 按位运算,即另一个左移和按位与。 (所以用 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 并将其位左移一位。” 00000001变成00000010

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

在您的情况下,如果 list.count 的值为 4,则循环将运行直到 i < (1<< 4) 即16 (00010000)

00000001 << 4 = 00010000(16)

表达式(1 << N)在 c# 中使用位移位

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

一个很好的工具年轻的鞭打者不了解位移如何工作的开发人员是程序员模式下的 Windows Calc,它可视化了位移对各种大小的有符号数的影响。 LshRsh函数分别等于<<>>

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

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

许多答案都暗示了这一点,但从未直接说明过......

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

例如,

十进制 5 二进制左移 1 是十进制 10,或十进制 5 加倍。

十进制 5 二进制左移 3 是十进制 40,或十进制 5 翻倍 3 次。

以前的答案已经解释它的作用,但似乎没有人猜测为什么 在我看来,这段代码的原因很可能是循环正在迭代列表成员的每个可能组合——这是我能理解为什么你想要迭代到 2^{list.list 的唯一原因。数数}。 因此,变量i将被错误命名:而不是索引(这是我通常将 'i' 解释为含义的意思),它的位表示列表中项目的组合,因此(例如)可以选择第一个项目,如果位的零i被设置( (i & (1 << 0)) != 0 )时,第二项如果一个位被设置( (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
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM