Почему в Java и C# есть операторы битового сдвига?

Является ли разница между целочисленным умножением (временно забывая о делении) по-прежнему в пользу сдвига, и если да, то насколько велика разница?

Это просто кажется такой низкоуровневой оптимизацией, даже если вы этого хотите, разве компилятор (C # / Java) для байт-кода или jit не должен его ловить в большинстве случаев?

Примечание. Я протестировал скомпилированный вывод для C# (с компилятором gmcs Mono C# версии 2.6.7.0), и в примерах умножения не использовался сдвиг для умножения даже при умножении на кратное 2.

C# http://csharp.pastebin.com/hcrRnPrb

cil http://csharp.pastebin.com/0js9F2c1

P.S. Я забыл, как может быть полезно использовать его для байтов, но все еще возникают проблемы с его использованием для чисел.


person Roman A. Taycher    schedule 01.10.2010    source источник
comment
Умножение — не единственное использование операторов битового сдвига.   -  person Cristian    schedule 01.10.2010
comment
Иногда операторы битового сдвига повышают ясность по сравнению с эквивалентом умножения.   -  person Kirk Woll    schedule 01.10.2010
comment
Вы смотрите на IL, вам действительно нужно увидеть машинный код после JIT-компиляции, чтобы определить, правильно ли оптимизирует их фреймворк.   -  person Ben Voigt    schedule 01.10.2010
comment
Кристиан, ты имеешь в виду разделение или ты говоришь о чем-то другом?   -  person Roman A. Taycher    schedule 01.10.2010


Ответы (8)


Вы правы, если операторы сдвига используются только как альтернатива умножениям, это следует оставить на усмотрение компилятора.

Я полагаю, вы пропустили такие приложения, как:

  • Шифрование/дешифрование
  • Расчет CRC
  • Манипуляции с растровыми изображениями (графика, блокировки базы данных)
  • Сжатие/декомпрессия
  • Настройка данных для аппаратных регистров
  • Изменить кодировку

и многое другое нуждается в битовом повороте для эффективной реализации без собственного кода.

person stacker    schedule 01.10.2010

Первая причина:

Иногда — в большинстве случаев — вы хотите обрабатывать целое число как число. Иногда целое число является удобным способом представления набора битов.

Умножение — это операция над числами.

Сдвиг — это операция над набором битов.

То, что существует связь между результатами умножения и результатами сдвига, не имеет особого значения. Операции логически отличаются.

Вторая причина:

C# и Java были разработаны, чтобы быть знакомыми разработчикам C, хотя и на поверхностном уровне. Поэтому общие идиомы из C были включены в C# и Java.

person Eric Lippert    schedule 01.10.2010
comment
С# и Java (особенно последняя) многое убрали из С и С++. - person Roman A. Taycher; 01.10.2010
comment
Что еще более важно, мне любопытно, почему вы хотите представить 2 байта как int, если это не должно быть числом. - person Roman A. Taycher; 01.10.2010
comment
@Roman: Потому что вы можете перемещать его (и другие операции) в два раза эффективнее, чем если бы вы сохранили два байта в отдельных переменных. - person Ben Voigt; 01.10.2010
comment
Я предполагаю, что если у вас есть только два effecieny, это не имеет большого значения, если у вас их больше, почему бы не использовать массив байтов? - person Roman A. Taycher; 01.10.2010
comment
@Roman, является ли что-то узким местом в производительности, нельзя обсуждать вне контекста. Если у вас есть несколько операций с двумя байтами, например. 1000 операций и несколько тысяч одновременных пользователей, тогда это будет иметь значение - person Rune FS; 01.10.2010
comment
Контекст - это то, что мне нужно, какой контекст дает значительный прирост производительности? - person Roman A. Taycher; 01.10.2010
comment
@Roman: Сигналы к/от внешних устройств: звуковая карта, ПЛК и т. д. - person GvS; 01.10.2010
comment
@Roman: из-за CIDR IP-адрес имеет смысл как последовательность битов, а не как числовое значение. (IP address) & (network mask) примерно в десять раз быстрее работает с 32-битными целыми числами, чем цикл по массиву байтов, и в четыре раза быстрее с 32-битными целыми числами, чем развернутый цикл. - person Ben Voigt; 01.10.2010

Если бы я хотел умножить число на 4, я бы написал * 4. Если бы я намеревался сдвинуть некоторые биты влево на 2 позиции, я бы написал << 2.

Повторный вопрос:

Почему в Java и C# есть операторы битового сдвига?

Я много работаю с двоичными данными, где я не думаю о целых числах и т. д. — только двоичные — и в этой области совершенно логично постоянно использовать операторы сдвига. .

Конечно, я мог бы ввести * 2 и т. д., но на самом деле я хочу сдвинуть биты.

Это распространено в ряде областей, где важны байты (например, графическое программирование, сериализация и т. д.).

Кроме того, существуют некоторые тонкости операций сдвига, когда вы не хотите вести себя как целое число, в частности при работе с ребрами... происходит, когда вы немного смещаете карту влево или смещаете вправо биты вглубь карты (-ve против +ve и т. д.) хорошо понятны, но критичны. Точно так же поведение целочисленного умножения checked/unckecked иногда очень важно.

person Marc Gravell    schedule 01.10.2010

Вы спрашиваете не о том, почему в С#/Java есть операторы битового сдвига, а о том, почему компилятор javac не оптимизирует умножения и деления со степенью двойки в битовые сдвиги.

Рефлекторная реакция на это заключается в том, что умножение и деление имеют другую семантику, чем битовые сдвиги, поэтому они не отображают 100% замену операций.

Кроме того, вы забыли дополнительный шаг компиляции, который происходит в JIT (HotSpot), где происходят всевозможные дополнительные оптимизации. Откровенно говоря, нет необходимости оптимизировать этот конкретный шаг, в отличие от C, где код находится в том виде, в каком его генерирует компилятор.

person Thorbjørn Ravn Andersen    schedule 01.10.2010

Потому что разработчики языка подумали, что было бы неплохо их иметь.

На самом деле не важно, что они эквивалентны какой-то другой операции и что компиляторы достаточно умны, чтобы эффективно реализовать операции. Если это то, к чему мы идем, то вам не нужно ничего, кроме ассемблера макросов и действительно хорошего оптимизатора времени компоновки, возможно, на виртуальной машине со сборщиком мусора. Это не те цели, которые обычно преследуют разработчики языков.

person SingleNegationElimination    schedule 01.10.2010

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

Посмотрите этот учебник – большинство примеров взяты из математических задач. Если вы просто делаете сайт или приложение с графическим интерфейсом, вам, вероятно, не нужно переключаться, но иногда вам действительно нужно...

person SPIRiT_1984    schedule 01.10.2010
comment
Я согласен с тем, что у битового сдвига есть область, где они облегчают чтение/запись кода, но вы могли бы обойтись без них и просто использовать *2^n или /2^n вместо ‹‹n и ››n. Так что они не обязательны, но приятно иметь - person Rune FS; 01.10.2010
comment
@Rune FS, -1››1 не совпадает с -1/2, независимо от того, расширен ли знак или нет. Переписывать операции сдвига, используя только математические операторы, на самом деле довольно неудобно. - person Jon Hanna; 01.10.2010
comment
@ Джон, вы упустили момент, который заключается в том, что они не требуются, но могут быть переписаны (и знаки не имеют смысла, когда речь идет о битовых шаблонах, поскольку они предполагают конкретную интерпретацию шаблона, который не является частью самого шаблона. Например, есть несколько битовые шаблоны, которые в данном контексте представляют -1, и все они представляют положительное целое число в разных контекстах и ​​часть файла, зашифрованного в еще одном контексте - person Rune FS; 01.10.2010
comment
@Rune FS, вы упустили мою мысль о том, что их нельзя переписать тривиально. Мы можем переписать любую инструкцию, используя только команду вычитания и ветвления, если она отрицательная, но есть веские причины, почему мы этого не делаем. Наконец, вы подтверждаете мою точку зрения, когда говорите об -1, поскольку именно вы смешиваете размышления о математике и размышлениях о битовых шаблонах, я утверждаю, что их лучше отделять друг от друга с помощью отдельных операторов. - person Jon Hanna; 01.10.2010
comment
@Jon Я заявляю в своем организационном комментарии, что считаю, что операторы сдвига - это хорошо, но в ответах говорится, что они необходимы, что не соответствует действительности. и они тривиальны для реализации оператора ›› (маска uint, места uint){маска возврата / (uint)Math.Pow(2,places); }. Что я и пытался объяснить выше. И, как вы сами сказали, мы можем переписать... Т.е. операторы сдвига не требуются, но их хорошо иметь - person Rune FS; 01.10.2010
comment
@Rune FS, не так тривиально для расширения знака. - person Jon Hanna; 01.10.2010
comment
@Jon, приведенная выше реализация работает для всех битовых масок. Как я уже сказал в своем первом ответе вам. Не совершайте ошибку, применяя то, как вы интерпретируете ввод/результат, к тому, как вы реализуете оператор. Приведенной выше реализации все равно, если вы дадите ей то, что вам кажется отрицательным целым числом. Он просто видит битовую маску и работает для всех битовых масок (при условии, что они не слишком длинные для представления uint) - person Rune FS; 01.10.2010
comment
@Руна ФС. Что ж, тогда он не делает того, что делает оператор ›› в C# или Java, потому что оба этих языка ›› ведут себя по-разному с отрицательными числами (и хотя неважно, что я думаю является отрицательным числом, имеет значение, что остальная часть фреймворка считает отрицательным числом). Вы не можете сказать, что мы можем заменить ››, а затем привести пример, который не заменяет ››. - person Jon Hanna; 01.10.2010

В дополнение к другим причинам, существует множество случаев, когда вам может потребоваться сдвиг (или другие битовые операции) для взаимодействия со сторонней библиотекой или удаленным приложением по сети.

person Seth    schedule 01.10.2010

Так что вы можете сдвигать биты влево и вправо. Что вы хотите, чтобы эти биты и их операции сдвига представляли, полностью зависит от вас.

person explorer    schedule 01.10.2010
comment
@ Руна FS... О ! чувак ... ха-ха-ха ... это была веселая ошибка. Спасибо за исправление. - person explorer; 01.10.2010