В комментарии этот ответ (который предлагает использовать операторы бит-сдвига над целым умножением/делением для производительности), я спросил, будет ли это на самом деле быстрее. В глубине моего сознания есть идея, что на каком-то уровне что-то будет достаточно умным, чтобы понять, что >> 1 и / 2 - это одна и та же операция. Однако теперь мне интересно, действительно ли это так, и если да, на каком уровне это происходит.
В тестовой программе создается следующий сравнительный CIL (с optimize on) для двух методов, которые соответственно делят и сдвигают свой аргумент:
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.2
  IL_0002:  div
  IL_0003:  ret
} // end of method Program::Divider
против
  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.1
  IL_0002:  shr
  IL_0003:  ret
} // end of method Program::Shifter
Поэтому компилятор С# испускает команды div или shr, не будучи умным. Теперь я хотел бы видеть фактический ассемблер x86, который производит JITter, но я понятия не имею, как это сделать. Возможно ли это?
изменить, чтобы добавить
Выводы
Спасибо за ответы, приняли тот из nobugz, потому что в нем содержится ключевая информация об этой опции отладчика. В конечном итоге для меня это было:
- Переключиться на конфигурацию Release
 -  В 
Tools | Options | Debuggerотключите параметр "Подавлять оптимизацию JIT при загрузке модуля" (т.е. мы хотим разрешить оптимизацию JIT) - В том же месте выключите "Включить только мой код" (т.е. мы хотим отладить весь код)
 -  Поместите оператор 
Debugger.Break()где-нибудь - Сборка сборки
 - Запустите .exe, а когда он сломается, отлаживается с использованием существующего экземпляра VS
 - Теперь в окне "Разборка" отображается фактический x86, который будет выполнен
 
Результаты были просвечивающими, если не сказать больше - оказывается, JITter действительно может сделать арифметику! Здесь отредактированы образцы из окна "Разборка". Различные методы -Shifter делятся на две степени с помощью >>; различные методы -Divider делятся на целые числа, используя /
 Console.WriteLine(string.Format("
     {0} 
     shift-divided by 2: {1} 
     divide-divided by 2: {2}", 
     60, TwoShifter(60), TwoDivider(60)));
00000026  mov         dword ptr [edx+4],3Ch 
...
0000003b  mov         dword ptr [edx+4],1Eh 
...
00000057  mov         dword ptr [esi+4],1Eh 
Оба метода статически-разделить на 2 не только были встроены, но фактические вычисления были сделаны JITter
Console.WriteLine(string.Format("
    {0} 
    divide-divided by 3: {1}", 
    60, ThreeDivider(60)));
00000085  mov         dword ptr [esi+4],3Ch 
...
000000a0  mov         dword ptr [esi+4],14h 
То же самое со статически-делением на 3.
Console.WriteLine(string.Format("
    {0} 
    shift-divided by 4: {1} 
    divide-divided by 4 {2}", 
    60, FourShifter(60), FourDivider(60)));
000000ce  mov         dword ptr [esi+4],3Ch 
...
000000e3  mov         dword ptr [edx+4],0Fh 
...
000000ff  mov         dword ptr [esi+4],0Fh 
И статически-разделите-на-4.
Лучшее:
Console.WriteLine(string.Format("
    {0} 
    n-divided by 2: {1} 
    n-divided by 3: {2} 
    n-divided by 4: {3}", 
    60, Divider(60, 2), Divider(60, 3), Divider(60, 4)));
0000013e  mov         dword ptr [esi+4],3Ch 
...
0000015b  mov         dword ptr [esi+4],1Eh 
...
0000017b  mov         dword ptr [esi+4],14h 
...
0000019b  mov         dword ptr [edi+4],0Fh 
Он встраивается, а затем вычисляет все эти статические деления!
Но что, если результат не статичен? Я добавил код для чтения целого числа из Консоли. Это то, что он производит для разделов на этом:
Console.WriteLine(string.Format("
    {0} 
    shift-divided by 2:  {1} 
    divide-divided by 2: {2}", 
    i, TwoShifter(i), TwoDivider(i)));
00000211  sar         eax,1 
...
00000230  sar         eax,1 
Итак, несмотря на то, что CIL отличается от других, JITTER знает, что деление на 2 сдвигается вправо на 1.
Console.WriteLine(string.Format("
    {0} 
    divide-divided by 3: {1}", i, ThreeDivider(i)));
00000283 idiv eax, ecx
И он знает, что вам нужно разделить, чтобы разделить на 3.
Console.WriteLine(string.Format("
    {0} 
    shift-divided by 4: {1} 
    divide-divided by 4 {2}", 
    i, FourShifter(i), FourDivider(i)));
000002c5  sar         eax,2 
...
000002ec  sar         eax,2 
И он знает, что деление на 4 сдвигается вправо на 2.
Наконец (лучшее снова!)
Console.WriteLine(string.Format("
    {0} 
    n-divided by 2: {1} 
    n-divided by 3: {2} 
    n-divided by 4: {3}", 
    i, Divider(i, 2), Divider(i, 3), Divider(i, 4)));
00000345  sar         eax,1 
...
00000370  idiv        eax,ecx 
...
00000395  sar         esi,2 
Он ввел метод и разработал лучший способ сделать что-то на основе статически доступных аргументов. Ницца.
Так что да, где-то в стеке между С# и x86, что-то достаточно умно, чтобы понять, что >> 1 и / 2 совпадают. И все это еще больше усугубило мое мнение о том, что добавление компилятора С#, JITter и CLR делает намного более умным, чем любые небольшие трюки, которые мы можем попробовать в качестве смиренных программистов приложений:)