在计算机中,整数以二进制数表示,即由若干 bits位(取值为 0 或 1 的数字)组成的序列。从概念上讲,该位序列在左侧是无限延伸的,最高位全为 0 或全为 1。按位运算会对该序列中的每一位单独操作。例如, shifting移位 操作会将整个序列向左或向右移动一位或多位,并保持原有模式。 Emacs Lisp 中的按位运算仅适用于整数。
ash(arithmetic shift算术移位)将整数 integer 的二进制位向左移动 count 位;若 count 为负数,则向右移动。左移会在右侧补 0;右移会丢弃最右侧的位。从整数运算角度看,ash 等价于将 integer 乘以
2**count,
然后向下取整(向负无穷方向)得到整数结果。
下面是 ash 分别左移、右移一位的示例。示例只展示低位二进制位,高位均与所示最高位保持一致。可以看到,左移一位等价于乘以 2,右移一位等价于除以 2 并向负无穷取整。
(ash 7 1) ⇒ 14
;; Decimal 7 becomes decimal 14.
...000111
⇒
...001110
(ash 7 -1) ⇒ 3
...000111
⇒
...000011
(ash -7 1) ⇒ -14
...111001
⇒
...110010
(ash -7 -1) ⇒ -4
...111001
⇒
...111100
左移或右移两位的示例:
; binary values (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 是 logical shift逻辑移位的缩写,将整数 integer 向左移动 count 位;若 count 为负数,则向右移动,空出的位一律补 0。若 count 为负,则 integer 必须是定长数(fixnum)或正的大数(bignum),且 lsh 会将负定长数视为无符号数处理:先减去两倍的 most-negative-fixnum 再移位,结果非负。这种特殊行为源于早期 Emacs 仅支持定长数的时代;现在更推荐使用 ash。
除了 integer 与 count 同时为负的情况外,lsh 与 ash 行为一致。下面示例聚焦这些例外情况,并假设使用 30 位定长数。
; binary values (ash -7 -1) ; -7 = ...111111111111111111111111111001 ⇒ -4 ; = ...111111111111111111111111111100 (lsh -7 -1) ⇒ 536870908 ; = ...011111111111111111111111111100
(ash -5 -2) ; -5 = ...111111111111111111111111111011 ⇒ -2 ; = ...111111111111111111111111111110 (lsh -5 -2) ⇒ 268435454 ; = ...001111111111111111111111111110
该函数返回所有参数的按位与结果:当且仅当所有参数的第 n 位都为 1 时,结果的第 n 位为 1。
例如,用 4 位二进制数表示,13 与 12 的按位与结果是 12:1101 与 1100 运算得到 1100。两个数最左侧两位都为 1,因此结果最左侧两位为 1;而最右侧两位至少有一个参数为 0,因此结果最右侧两位为 0。
所以,
(logand 13 12)
⇒ 12
若 logand 无参数,返回 −1。该 logand 数是按位与的单位元,因为其二进制全为 1。若 logand 只传入一个参数,直接返回该参数。
; binary values (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
该函数返回所有参数的按位或结果:当且仅当至少一个参数的第 n 位为 1时,结果的第 n 位为 1。无参数时返回 0,是该运算的单位元。logior 只传入一个参数时,直接返回该参数。
; binary values (logior 12 5) ; 12 = ...001100 ; 5 = ...000101 ⇒ 13 ; 13 = ...001101
(logior 12 5 7) ; 12 = ...001100 ; 5 = ...000101 ; 7 = ...000111 ⇒ 15 ; 15 = ...001111
该函数返回所有参数的按位异或结果:当且仅当该位为 1 的参数个数是奇数时,结果的第 n 位为 1。无参数时返回 0,是该运算的单位元。logxor 只传入一个参数时,直接返回该参数。
; binary values (logxor 12 5) ; 12 = ...001100 ; 5 = ...000101 ⇒ 9 ; 9 = ...001001
(logxor 12 5 7) ; 12 = ...001100 ; 5 = ...000101 ; 7 = ...000111 ⇒ 14 ; 14 = ...001110
该函数返回参数的按位取反结果:当且仅当 integer 的第 n 位为 0时,结果的第 n 位为 1,反之亦然。结果等于:−1 − integer。
(lognot 5)
⇒ -6
;; 5 = ...000101
;; becomes
;; -6 = ...111010
该函数返回 integer整数 的 Hamming weight汉明重量:即 integer 二进制表示中 1 的个数。若 integer 为负数,则返回其二进制补码表示中 0 的个数。结果始终非负。
(logcount 43) ; 43 = ...000101011 ⇒ 4 (logcount -43) ; -43 = ...111010101 ⇒ 3