Перейти к содержимому

Битовые операции

Число как набор битов: маски, сдвиги и почему сдвиг на 64 ничего не меняет

Любое целое число — это набор битов: 12 — это 1100, 10 — это 1010. Шесть операций op работают не с числом целиком, а с каждым битом по отдельности.

Это нужно нечасто, но когда нужно — заменить нечем: несколько признаков в одном числе, проверка «включён ли такой-то бит», быстрое умножение на степень двойки.

тик 0
Операция0
=
Операция1
=
Операция2
=
Операция3
=
Операция4
=
Операция5
=
@counter0number
маскаnullnull
обеnullnull
разныеnullnull
сдвигnullnull
обратноnullnull
инвертnullnull
Операция В блоке Что делает 12 и 10
and b-and бит остаётся, если он есть в обоих 8 (1000)
or or бит остаётся, если он есть хоть в одном 14 (1110)
xor xor бит остаётся, если он есть ровно в одном 6 (0110)
not flip все биты наоборот −6 из 5
shl << сдвиг влево: умножение на 2 столько раз 8 из 1 и 3
shr >> сдвиг вправо: деление на 2 столько раз 1 из 8 и 3

Столбец «В блоке» стоит прочесть внимательно: побитовое «и» подписано b-and, потому что and в списке уже занято логическим «и», а побитовая инверсия — flip, потому что not занято сравнением «не равно». Имена в справочниках и знаки на кнопках здесь расходятся сильнее всего.

Сдвиг — самый понятный из шести: shl 1 3 двигает единственный бит на три позиции влево и превращает 1 в 8. Обратный shr возвращает 8 в 1.

Перед битовой операцией число приводится к целому: дробная часть отбрасывается, and от 12.7 и 10 даст те же 8, что и от 12.

Целое при этом длинное, 64-битное, и знаковое — от −2⁶³ до 2⁶³−1.

тик 0
Операция0
=
Операция1
=
Операция2
=
@counter0number
переборnullnull
знакnullnull
беззнакnullnull

shl 1 64 даёт 1, а не ноль. У сдвига берутся только младшие шесть битов второго числа, то есть остаток от деления на 64. Сдвиг на 64 — это сдвиг на 0, сдвиг на 65 — на 1. Ноль не получится никак.

shr −8 1 даёт −4, а не большое число. shr знаковый: он двигает биты вправо, а слева дописывает знак, поэтому отрицательное остаётся отрицательным. Деление пополам работает и для минусов.

ushr −1 60 даёт 15. А вот ushr знак не бережёт: он считает число беззнаковым, и −1 для него — это 64 единичных бита. Сдвинули на 60, осталось четыре: 15.

Главный случай — уместить несколько чисел в одно. Переменных у процессора много, а мест, куда можно положить число для другого процессора, мало: ячейка памяти, флаг юнита. Сдвигами и or в одно число складывают несколько, а shr и and достают обратно.

Сколько чисел туда влезет, решает тот самый предел: на всё про всё 53 бита. Разбор — в уроке «Число внутри».

Неофициальный проект, с Anuke не связан. Спрайты, шрифты и переводы Mindustry © Anuke, используются по GPL-3.0; Fira Code — по OFL-1.1. Код сайта — GPL-3.0.