假设我有一个整数,如二进制的109,1101101。如何迭代这个数字的位,例如:[64,32,8,4,1]?在lisp中这样做的好方法是什么?我应该通过添加一个案例来修改for宏,还是应该将整数转换为位向量或列表?
答案 0 :(得分:6)
如果你只想处理“1”,那么如果那些很少,那么循环遍历所有位是没有效率的。这就是我在这种情况下所做的事情
(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))))
它使用了很好的2补码事实,即bit-anding一个数字,而它的相反值返回最低有效设置位,而bit-anding数字和一个小于数字的数字将这个最低有效设置位归零。
请注意,此处理从最低有效位设置到最高有效位(在您的示例中使用了相反的顺序)
答案 1 :(得分:5)
查看logbitp,它允许您访问整数的各个位。例如,
(loop for i below (integer-length 109)
collect (if (logbitp i 109) 1 0))
=> (1 0 1 1 0 1 1)
答案 2 :(得分:0)
这可能不太复杂,但会做到。请注意,在使用之前需要测试“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
另请注意,对于大数字“灰烬”可能会变得相当昂贵,在这种情况下,您可能想要使用6502的变体。
答案 3 :(得分:-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)