Я должен сказать, что у меня никогда не было причины использовать побитовые операторы, но я уверен, что некоторые операции, которые я выполнил, были бы более эффективно с ними. Как "переключение" и "OR-ing" помогли вам решить проблему более эффективно?
О каких ПОЛЕЗНЫХ ПОСЛЕДОВАТЕЛЬНЫХ ПОДАВЛЕНИЯХ кода оператора должен знать разработчик?
Ответ 1
Посмотрите знаменитый Бит Twiddling Hacks
Большинство размножающихся/делящих не нужны - компилятор сделает это автоматически, и вы просто смутите людей.
Но есть множество типов "check/set/toggle bit N", которые очень полезны, если вы работаете с аппаратными или коммуникационными протоколами.
Ответ 2
Использование побитовых операций над строками (символами)
Преобразовать письмо в в нижнем регистре:
-
OR
по пространству = >(x | ' ')
- Результат всегда строчный, даже если буква уже имеет строчные буквы
- например.
('a' | ' ') => 'a'
;('a' | ' ') => 'a'
Преобразовать письмо в в верхнем регистре:
-
AND
by underline = >(x & '_')
- Результат всегда в верхнем регистре, даже если буква уже прописная.
- например.
('a' & '_') => 'A'
;('a' & '_') => 'A'
Инвертировать регистр букв:
-
XOR
по пространству = >(x ^ ' ')
- например.
('a' ^ ' ') => 'A'
;('a' ^ ' ') => 'A'
Буква позиция в алфавите:
-
AND
chr(31)
/binary('11111')
/(hex('1F')
= >(x & "\x1F")
- Результат в диапазоне 1..26, регистр букв не важен
- например.
('a' & "\x1F") => 1
;('B' & "\x1F") => 2
Получить букву position в алфавите (только для букв Только для верхнего):
-
AND
на?
= >(x & '?')
илиXOR
на@
= >(x ^ '@')
- например.
('C' & '?') => 3
;('Z' ^ '@') => 26
Получить букву позицию в алфавите (только для строчных):
-
XOR
с помощью обратного хода /chr(96)
/binary('1100000')
/hex('60')
= >(x ^ '`')
- например.
('d' ^ '`') => 4
;('x' ^ '`') => 25
Примечание: использование чего-либо, кроме английских букв, приведет к результатам мусора
Ответ 3
- Побитовые операции с целыми числами (int)
Получить максимальное целое число
int maxInt = ~(1 << 31);
int maxInt = (1 << 31) - 1;
int maxInt = (1 << -1) - 1;
Получить минимальное целое число
int minInt = 1 << 31;
int minInt = 1 << -1;
Получить максимальную длину
long maxLong = ((long)1 << 127) - 1;
Умножается на 2
n << 1; // n*2
Разделено на 2
n >> 1; // n/2
Умножается на m-ю степень 2
n << m;
Разделенная на m-ю степень 2
n >> m;
Проверить нечетное число
(n & 1) == 1;
Обмен двумя значениями
a ^= b;
b ^= a;
a ^= b;
Получить абсолютное значение
(n ^ (n >> 31)) - (n >> 31);
Получить максимум двух значений
b & ((a-b) >> 31) | a & (~(a-b) >> 31);
Получить минимум двух значений
a & ((a-b) >> 31) | b & (~(a-b) >> 31);
Проверьте, имеют ли обе тот же знак
(x ^ y) >= 0;
Вычислить 2 ^ n
2 << (n-1);
Является ли факториал 2
n > 0 ? (n & (n - 1)) == 0 : false;
Modulo 2 ^ n против m
m & (n - 1);
Получить средний
(x + y) >> 1;
((x ^ y) >> 1) + (x & y);
Получить m-й бит n (от низкого до высокого)
(n >> (m-1)) & 1;
Установите m-й бит n в 0 (от низкого до высокого)
n & ~(1 << (m-1));
n + 1
-~n
n - 1
~-n
Получить контрастность
~n + 1;
(n ^ -1) + 1;
, если (x == a) x = b; if (x == b) x = a;
x = a ^ b ^ x;
Ответ 4
Там только три, которые я когда-либо использовал с любой частотой:
-
Установите бит: a | = 1 < бит;
-
Очистить бит: a & = ~ (1 < бит);
-
Проверьте, что бит установлен: a и (1 < бит);
Ответ 5
Вопросы вычислительные: идеи, алгоритмы, исходный код, Йорг Арндт (PDF). Эта книга содержит множество вещей, я нашел ее по ссылке http://www.hackersdelight.org/
Среднее значение без переполнения
Процедура вычисления среднего (x + y)/2 двух аргументы x и y
static inline ulong average(ulong x, ulong y) // Return floor( (x+y)/2 ) // Use: x+y == ((x&y)<<1) + (x^y) // that is: sum == carries + sum_without_carries { return (x & y) + ((x ^ y) >> 1); }
Ответ 6
Вы можете сжимать данные, например. набор целых чисел:
- Посмотрите, какие целые значения появляются чаще в коллекции
- Используйте короткие битовые последовательности для представления значений, которые появляются более часто (и более длинные последовательности бит для представления значений, которые появляются менее часто )
- Объединение бит-последовательностей: так, например, первые 3 бита в результирующем потоке бит могут представлять одно целое число, затем следующие 9 бит другого целого числа и т.д.
Ответ 7
Подсчет бит бит, поиск минимального/наивысшего бита набора, поиск бит nth-from-top/bottom и других может быть полезным, и стоит посмотреть бит-twiddling hacks.
Тем не менее, такого рода вещи не являются повседневными. Полезно иметь библиотеку, но даже тогда наиболее распространенные виды использования являются косвенными (например, с использованием контейнера битов). Кроме того, в идеале это будут стандартные библиотечные функции - многие из них лучше обрабатываются с помощью специализированных инструкций CPU на некоторых платформах.
Ответ 8
1) Разделить/Умножить на мощность 2
foo >>= x;
(разделите по мощности 2)
foo <<= x;
(умножить на мощность 2)
2) Swap
x ^= y;
y = x ^ y;
x ^= y;
Ответ 9
В то время как умножение/деление на сдвиг кажется отличным, единственное, что мне нужно было время от времени - сжимать булевы в биты. Для этого вам нужно поразрядное AND/OR и, возможно, смещение/инвертирование битов.
Ответ 10
Мне нужна функция для округления чисел до следующей максимальной мощности в два, поэтому я посетил сайт Bit Twiddling, который несколько раз поднимался и придумывал следующее:
i--;
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
i++;
Я использую его по типу size_t
. Вероятно, он не будет хорошо воспроизводить подписанные типы. Если вы беспокоитесь о переносимости платформ с различными размерами, покройте свой код директивами #if SIZE_MAX >= (number)
в соответствующих местах.
Ответ 11
Я использовал побитовые операторы для эффективного выполнения расчетов расстояний для битовых строк. В моем приложении битрейты использовались для представления позиций в дискретизированном пространстве (octree, если вы заинтересованы, закодированы с помощью Заказ Morton). Расчет расстояний был необходим, чтобы узнать, попали ли точки на сетке в пределах определенного радиуса.