Axiom Справочник языка

Глава 3 · Выражения и операции

Побитовые операции и сдвиги

Флаги, маски и упакованные поля удобно хранить в отдельных разрядах целого числа. Побитовые операции читают и изменяют эти разряды у INTEGER и LONG: маской выделяют, устанавливают и очищают выбранные позиции, а сдвиги перемещают их влево или вправо в пределах ширины типа.

Нумерация разрядов и знак

INTEGER содержит 32 разряда, LONG содержит 64. Отсчёт начинается справа с нуля: разряд 0 соответствует единице, разряд 1 соответствует двум, разряд 2 соответствует четырём. Старший разряд, 31 или 63, определяет знак.

Отрицательные целые представлены дополнительным кодом, поэтому число -1 имеет единицы во всех разрядах своего типа. Побитовый результат также имеет целочисленный тип, а логические значения BOOLEAN к этим разрядам не приравниваются. Различия описаны в статье BOOLEAN, двоичная и шестнадцатеричная запись — в статье систем счисления.

Формы операций и тип результата

Каждая запись ниже обозначает отдельную целочисленную форму операции. В этих формах операнд должен иметь тип INTEGER или LONG:

NOT <целое выражение>
<левое целое> AND <правое целое>
<левое целое> OR <правое целое>
<левое целое> XOR <правое целое>
<левое целое> EQV <правое целое>
<левое целое> IMP <правое целое>

NOT сохраняет тип своего операнда. Бинарная операция над двумя INTEGER возвращает INTEGER, а если один операнд LONG, второй расширяется до LONG и результат получает тип LONG. При расширении отрицательного INTEGER значение сохраняется: добавленные старшие разряды заполняются единицами.

DOUBLE, DECIMAL, STRING и смесь BOOLEAN с целым числом в этих формах недопустимы. У NOT есть отдельная логическая форма с одним BOOLEAN, а у AND, OR, XOR, EQV и IMP — с двумя: она возвращает BOOLEAN, не обрабатывая числовые разряды, и её полный договор находится в статье BOOLEAN. ANDALSO и ORELSE принимают только BOOLEAN и побитового действия не имеют.

Правило для одной пары разрядов

NOT заменяет каждый ноль единицей, а каждую единицу нулём. Остальные операции применяют одно и то же правило к каждой паре соответствующих разрядов:

ABANDORXOREQVIMP
0000011
0101101
1001100
1111011

AND оставляет единицу только при двух единицах, OR устанавливает её при хотя бы одной. XOR выбирает различающиеся разряды, EQV — совпадающие, IMP очищает разряд только при единице слева и нуле справа. Нули и единицы в таблице являются битами, а не литералами TRUE и FALSE.

NOT применяется ко всей ширине типа: NOT 0 равно -1, NOT -1 равно 0.

Выбор разрядов маской

Маска представляет выбранные позиции единицами: AND сохраняет в числе только эти позиции, OR устанавливает их, XOR переключает, а AND с инверсией маски очищает. В примере результаты выводятся в двоичном виде:

DIM value AS INTEGER = &B1010
DIM mask AS INTEGER = &B1100
PRINT $"{value AND mask:B4}"
PRINT $"{value OR mask:B4}"
PRINT $"{value XOR mask:B4}"
PRINT $"{value AND NOT mask:B4}"

Результат:

1000
1110
0110
0010

AND, OR, XOR, EQV и IMP вычисляют оба операнда слева направо и не пропускают правый по значению левого.

Ширина результата

Разрядность определяется типом, а не числом цифр в литерале: &HFFFFFFFF является положительным LONG 4294967295, поэтому его инверсия NOT &HFFFFFFFF обрабатывает 64 разряда и равна -4294967296. INTEGER со всеми единичными разрядами задаётся значением -1 или выражением NOT 0.

Нужный тип должен быть задан до операции: выражение CLNG(1) << 32 сдвигает LONG и даёт 4294967296, а объявление DIM wide AS LONG = 1 << 32 сначала сдвигает INTEGER и только затем расширяет результат 1 до LONG.

Сдвиг влево и вправо

<целое значение> << <целое количество разрядов>
<целое значение> >> <целое количество разрядов>

Левый операнд INTEGER или LONG задаёт значение и тип результата, правый операнд INTEGER или LONG — количество разрядов. Сдвиг влево отбрасывает вышедшие за ширину биты и добавляет нули справа; сдвиг вправо сохраняет знак, заполняя старшие позиции отрицательного числа единицами, а неотрицательного — нулями.

Количество после получения INTEGER должно находиться от 0 до 63, иначе выдаётся MB3005. Для INTEGER используются только пять младших битов допустимого количества: 32 действует как 0, 33 как 1, 63 как 31; для LONG каждое количество от 0 до 63 используется непосредственно.

Если количество имеет тип LONG, сначала сохраняются лишь его младшие 32 бита, затем проверяется полученный INTEGER: поэтому 4294967296 и -4294967296 превращаются в 0, а 4294967297 превращается в 1. Проверяется полученное количество, а не исходная 64-разрядная величина, поэтому количество задаётся непосредственно в пределах от 0 до 63.

ВыражениеРезультат
1 << 31-2147483648
1 << 321
CLNG(1) << 324294967296
CLNG(1) << 63-9223372036854775808
-8 >> 2-2
-1 >> 1-1
1 << 64MB3005

Сдвиг не проверяет арифметическое переполнение: сложение INTEGER 2147483647 + 1 вызывает MB3008, а 2147483647 << 1 возвращает -2 после отбрасывания вышедших разрядов.

Сочетание с другими операциями

Степень ^ имеет больший приоритет, чем NOT, а сам NOT выполняется раньше умножения, сложения, сдвигов и сравнений. Сдвиги связываются слабее сложения, но сильнее сравнений; затем следуют AND, XOR, OR, EQV и IMP.

Скобки явно отделяют маску от проверки: (value AND mask) <> 0. Полный порядок приведён в таблице приоритетов.

Диагностика

  • MB2003: неподходящий тип операнда, например смесь BOOLEAN с INTEGER или количество сдвига типа DOUBLE.
  • MB3005: количество после преобразования в INTEGER находится вне диапазона от 0 до 63.
  • MB2018: литерал не помещается в ожидаемый целочисленный тип.
  • MB3008: переполнение соседней арифметической операции; отбрасывание разрядов при сдвиге этим кодом не диагностируется.

Запускаемые примеры

См. также

Для разрядов и сдвигов служат системы счисления и операции и приоритет. Логические значения описаны в статье BOOLEAN.