Что означают две левые угловые скобки "<<" в C #? - PullRequest
43 голосов
/ 22 марта 2010

В основном вопросы в названии. Я смотрю на исходный код MVC 2:

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

и мне просто интересно, что делает двойная левая угловая скоба <<.

Ответы [ 14 ]

131 голосов
/ 29 января 2014

Когда вы пишете

1 << n

Вы сдвинули битовую комбинацию 000000001 на n раз влево и таким образом положили n в показатель степени 2:

2^n

So

1 << 10

На самом деле

1024

Для списка, скажем, 5 элементов ваш for будет повторяться 32 раза.

82 голосов
/ 29 января 2014

Это называется 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
60 голосов
/ 22 марта 2010

Это будет оператор побитового сдвига влево .

Для каждого сдвига влево значение эффективно умножается на 2. Так, например, запись value << 3 умножит значение на 8.

Что он действительно делает внутри, так это перемещает все действительные биты значения в одно место. Так что, если у вас есть значение 12 (десятичное), в двоичном виде это 00001100; сдвиг его влево на одно место превратит это в 00011000 или 24.

57 голосов
/ 29 января 2014

Это Битовый сдвиг влево Он работает путем смещения цифр двоичного эквивалента числа на заданные (правые) числа.

так:

temp = 14 << 2

двоичный эквивалент 14 равен 00001110 смещение его 2 раза означает сдвиг нуля с правой стороны и смещение каждой цифры влево, что делает его 00111000 равным 56.

visual

В вашем примере:

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)

36 голосов
/ 22 марта 2010

Это оператор влево . Он сдвигает битовую комбинацию левого операнда влево на количество двоичных цифр, указанных в правом операнде.

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)

23 голосов
/ 29 января 2014

Целью цикла, скорее всего, является генерация или работа со всеми подмножествами набора элементов в списке. И тело цикла, скорее всего, также имеет хороший бит (хар хар) побитовых операций, а именно, еще один сдвиг влево и побитовый-и. (Так что переписать его, чтобы использовать Pow, было бы глупо, я с трудом могу поверить, что было так много людей, которые на самом деле предлагали это.)

15 голосов
/ 22 марта 2010

Это битовое смещение. По сути, это просто перемещение битов влево путем добавления нулей к правой стороне.

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

12 голосов
/ 29 января 2014

В дополнение к ответу 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++)

и т. Д.

9 голосов
/ 22 марта 2010

«Сдвиг бит влево». 1 << 0 означает «принять целое значение 1 и сдвинуть его биты влево на ноль». Т.е. 00000001 остается без изменений. 1 << 1 означает «принять целое значение 1 и сдвинуть его биты влево на одно место». 00000001 становится 00000010.

8 голосов
/ 29 января 2014

Это (<<) битовый оператор сдвига влево, он перемещает битовые значения двоичного объекта.Левый операнд указывает значение, которое должно быть смещено, а правый операнд указывает количество позиций, на которые должны быть сдвинуты биты в значении. </p>

В вашем случае, если значение list.count равно 4, циклработать до I <(1 << 4), что составляет <strong>16 (00010000)

00000001 << 4 = 00010000 (16) </p>

...