3.8 Побитовые операции над целыми числами

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

Побитовые операции в Emacs Lisp применимы только к целым числам.

Функция: ash целое-число количество

ash (арифметический сдвиг) сдвигает биты в целом-числе влево на количество позиций или вправо, если количество отрицательно. Сдвиг влево вводит нулевые биты справа; сдвиг вправо отбрасывает крайние правые биты. Рассматриваемая как операция над целыми числами, ash умножает целое-число на 2**количество, а затем преобразует результат в целое число округлением вниз, в сторону минус бесконечности.

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

(ash 7 1) ⇒ 14
;; Десятичное 7 становится десятичным 14.
…000111
     ⇒
…001110

(ash 7 -1) ⇒ 3
…000111
     ⇒
…000011

(ash -7 1) ⇒ -14
…111001
     ⇒
…110010

(ash -7 -1) ⇒ -4
…111001
     ⇒
…111100

Вот примеры сдвига влево или вправо на два бита:

                  ;         двоичные значения
(ash 5 2)         ;   5  =  …000101
     ⇒ 20         ;      =  …010100
(ash -5 2)        ;  -5  =  …111011
     ⇒ -20        ;      =  …101100
(ash 5 -2)
     ⇒ 1          ;      =  …000001
(ash -5 -2)
     ⇒ -2         ;      =  …111110
Функция: lsh целое-число количество

lsh, что является сокращением для логического сдвига, сдвигает биты в целом-числе влево на количество позиций или вправо, если количество отрицательно, вставляя нули в освобождающиеся биты. Если количество отрицательно, то целое-число должно быть либо фикснумом, либо положительным бигнумом, и lsh обрабатывает отрицательный фикснум так, как если бы он был беззнаковым, вычитая удвоенное most-negative-fixnum перед сдвигом, что даёт неотрицательный результат. Это странное поведение ведёт свою историю с тех времён, когда Emacs поддерживал только фикснумы; в наши дни ash является лучшим выбором.

Поскольку lsh ведёт себя как ash, за исключением случаев, когда и целое-число, и количество отрицательны, следующие примеры сосредоточены на этих исключительных случаях. В этих примерах предполагаются 30-битные фикснумы.

                 ;      двоичные значения
(ash -7 -1)      ; -7 = …111111111111111111111111111001
     ⇒ -4        ;    = …111111111111111111111111111100
(lsh -7 -1)
     ⇒ 536870908 ;    = …011111111111111111111111111100
(ash -5 -2)      ; -5 = …111111111111111111111111111011
     ⇒ -2        ;    = …111111111111111111111111111110
(lsh -5 -2)
     ⇒ 268435454 ;    = …001111111111111111111111111110
Функция: logand &rest целые-числа-или-маркеры

Эта функция возвращает побитовое И аргументов: n-й бит равен 1 в результате тогда и только тогда, когда n-й бит равен 1 во всех аргументах.

Например, используя 4-битные двоичные числа, побитовое И 13 и 12 равно 12: 1101 в комбинации с 1100 даёт 1100. В обоих двоичных числах два крайних левых бита равны 1, поэтому два крайних левых бита возвращаемого значения также равны 1. Однако для двух крайних правых битов каждый равен 0 хотя бы в одном из аргументов, поэтому два крайних правых бита возвращаемого значения равны 0.

Следовательно,

(logand 13 12)
     ⇒ 12

Если logand не передано ни одного аргумента, она возвращает значение −1. Это число является нейтральным элементом для logand, поскольку его двоичное представление состоит целиком из единиц. Если logand передан только один аргумент, она возвращает этот аргумент.

                   ;        двоичные значения

(logand 14 13)     ; 14  =  …001110
                   ; 13  =  …001101
     ⇒ 12         ; 12  =  …001100

(logand 14 13 4)   ; 14  =  …001110
                   ; 13  =  …001101
                   ;  4  =  …000100
     ⇒ 4          ;  4  =  …000100

(logand)
     ⇒ -1         ; -1  =  …111111
Функция: logior &rest целые-числа-или-маркеры

Эта функция возвращает побитовое включающее ИЛИ своих аргументов: n-й бит равен 1 в результате тогда и только тогда, когда n-й бит равен 1 хотя бы в одном из аргументов. Если аргументов нет, результат равен 0, что является нейтральным элементом для этой операции. Если logior передан только один аргумент, она возвращает этот аргумент.

                   ;        двоичные значения

(logior 12 5)      ; 12  =  …001100
                   ;  5  =  …000101
     ⇒ 13         ; 13  =  …001101

(logior 12 5 7)    ; 12  =  …001100
                   ;  5  =  …000101
                   ;  7  =  …000111
     ⇒ 15         ; 15  =  …001111
Функция: logxor &rest целые-числа-или-маркеры

Эта функция возвращает побитовое исключающее ИЛИ своих аргументов: n-й бит равен 1 в результате тогда и только тогда, когда n-й бит равен 1 в нечётном числе аргументов. Если аргументов нет, результат равен 0, что является нейтральным элементом для этой операции. Если logxor передан только один аргумент, она возвращает этот аргумент.

                   ;        двоичные значения

(logxor 12 5)      ; 12  =  …001100
                   ;  5  =  …000101
     ⇒ 9          ;  9  =  …001001

(logxor 12 5 7)    ; 12  =  …001100
                   ;  5  =  …000101
                   ;  7  =  …000111
     ⇒ 14         ; 14  =  …001110
Функция: lognot целое-число

Эта функция возвращает побитовое дополнение своего аргумента: n-й бит равен единице в результате тогда и только тогда, когда n-й бит равен нулю в целом-числе, и наоборот. Результат равен −1 − целое-число.

(lognot 5)
     ⇒ -6
;;  5  =  …000101
;; становится
;; -6  =  …111010
Функция: logcount целое-число

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

(logcount 43)     ;  43 = …000101011
     ⇒ 4
(logcount -43)    ; -43 = …111010101
     ⇒ 3