#math #operators #bitwise-operators
#математика #операторы #побитовые операторы
Вопрос:
Я нашел несколько примеров исходного кода, где автор, похоже, использует побитовый amp;
оператор вместо %
operator . Однако, когда я попробовал x amp; 4
, это не дало того же значения, x % 5
что и .
Комментарии:
1. @user988052 все еще есть. на 10% быстрее под .NET (только что протестировано), код здесь ideone.com/BLqZP (но обратите внимание, что на ideone разница намного меньше). Выпуск запуск без отладчика.
2. @user988052: побитовое и по-прежнему быстрее, чем любая
mod
реализация общего назначения, которая должна обрабатывать все числа. Но эта оптимизация настолько хорошо известна и проста, что многие компиляторы реализуют ее, так что да. @xanatos: обязательно дайте JIT сначала прогреться при тестировании.3. @xanatos: когда я говорю о «намного быстрее» в те дни, я говорю о побитовом использовании одного или двух циклов процессора и по модулю, используя оставшуюся часть div в регистре, для чего требуется около 20 циклов процессора, если не больше. Поэтому, когда я имел в виду «намного быстрее» , я имел в виду почти на порядок быстрее (в 10 раз, если не намного больше, в зависимости от аппаратного обеспечения). Я не говорю о каких-то 10%, которые, как указал Делнан, в любом случае могут быть оптимизированы автоматически в настоящее время ; )
4. @delnan Вау!! Это правда!!! Когда тепло!!! это тепло !! Нет, никаких различий! Попробовал цикл 100 раз и посмотрел только на последний тест. C # не полностью оптимизирует amp; и %
5. Компиляторы могут выполнять эту оптимизацию только для значений без знака или для значений со знаком, которые, как известно, являются положительными. Это означает, что иногда человек может выполнить эту оптимизацию в случае, когда компилятор не может (потому что у человека есть априорные знания, которых не хватает компилятору).
Ответ №1:
Это работает только для степеней 2.
В общем:
x MOD 2^n
эквивалентно:
x AND (2^n - 1)
Также обратите внимание, что это может быть верно только для x >= 0
, в зависимости от вашего определения MOD
for x < 0
.
Чтобы понять, почему это работает, рассмотрим, что такое MOD на самом деле — это просто остаток после выполнения целочисленного деления. В случае деления на 2 ^ n мы фактически просто сдвигаем двоичное значение вправо на n бит и отбрасываем любые младшие биты, которые сдвигаются, например, для 8-битного двоичного числа
a b c d e f g h
если мы разделим на 4 = 2 ^ 2, то мы сдвинемся вправо на 2 бита:
0 0 a b c d e f
Остаток ( g h
) был выброшен в результате целочисленного деления.
Если бы мы хотели узнать остаток, то мы могли бы просто извлечь биты g h
, применив маску 0 0 0 0 0 0 1 1
:
a b c d e f g h
AND 0 0 0 0 0 0 1 1
= 0 0 0 0 0 0 g h
Обратите внимание, что has имеет значение 3, которое в общем случае равно всего лишь 2 ^ n — 1.
Давайте попробуем это с некоторыми вещественными числами. Предположим, мы хотим вычислить 42/4 и получить как частное, так и остаток:
42 = 0 0 1 0 1 0 1 0
Чтобы получить частное, мы сдвигаем вправо на 2 бита:
42 / 4 (decimal)
= 0 0 1 0 1 0 1 0 >> 2
= 0 0 0 0 1 0 1 0
= 10 (decimal)
42 MOD 4 (decimal)
= 0 0 1 0 1 0 1 0 AND 0 0 0 0 0 0 1 1
= 0 0 0 0 0 0 1 0
= 2 (decimal)
Итак, 42/4 = 10 остаток 2.
Ответ №2:
Ответ довольно простой, попробуйте мыслить двоично.
0000 = 0 AND 11 = 0000 = 0
0001 = 1 AND 11 = 0001 = 1
0010 = 2 AND 11 = 0010 = 2
0011 = 3 AND 11 = 0011 = 3
0100 = 4 AND 11 = 0000 = 0
0101 = 5 AND 11 = 0001 = 1
0110 = 6 AND 11 = 0010 = 2
0111 = 7 AND 11 = 0011 = 3
… и так далее.
Это дает тот же результат, что и напоминание (% — остаток, формально, а не модуль). Он работает только со степенями 2 и только для нулевых и положительных чисел.