假设我有一个整数,例如109,1101101的二进制表示。如何迭代这个数字的位,例如:[64,32,8,4,1]?在Lisp中应该如何做?我应该通过添加一个case来修改for宏,还是应该将整数转换为位向量或列表?
(defmacro do-bits ((var x) &rest body)
"Evaluates [body] forms after binding [var] to each set bit in [x]"
(let ((k (gensym)))
`(do ((,k ,x (logand ,k (1- ,k))))
((= ,k 0))
(let ((,var (logand ,k (- ,k))))
,@body))))
请看logbitp,它允许您访问整数的单个位。例如:
(loop for i below (integer-length 109)
collect (if (logbitp i 109) 1 0))
=> (1 0 1 1 0 1 1)
这可能不太复杂,但足以胜任。请注意,在使用它之前,您需要测试 `zerop',因为如果您使用零调用它,则不会调用迭代回调函数。
(defun iterate-bits-of (x handler)
(unless (zerop x)
(and (funcall handler (logand x 1))
(iterate-bits-of (ash x -1) handler))))
(iterate-bits-of
#b1101101
#'(lambda (x) (not (format t "bit ~b~&" x))))
;; bit 1
;; bit 0
;; bit 1
;; bit 1
;; bit 0
;; bit 1
;; bit 1
( defun firstbit (x)
( logand x (- x)))
( defun ones (x)
( do (( bit (firstbit x) (firstbit x)) bits)
(( zerop bit) bits)
( setq bits (cons bit bits))
( setq x (logxor x bit))))
* (ones 109)
(64 32 8 4 1)