循环整数位的lisp方法

时间:2012-05-04 08:35:11

标签: for-loop lisp common-lisp bit-manipulation sbcl

假设我有一个整数,如二进制的109,1101101。如何迭代这个数字的位,例如:[64,32,8,4,1]?在lisp中这样做的好方法是什么?我应该通过添加一个案例来修改for宏,还是应该将整数转换为位向量或列表?

4 个答案:

答案 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)