Reputation: 8688
Suppose I have an integer such as 109, 1101101 in binary. How do I iterate over bits of this number, eg: [64, 32, 8, 4, 1]? What would be a good way of doing that in lisp? Should I modify the for macro a bit by adding a case or should I just convert the integer into a bit-vector or a list?
Upvotes: 3
Views: 1206
Reputation: 1220
( 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))))
provides
* (ones 109)
(64 32 8 4 1)
Upvotes: -1
Reputation:
This is probably less sophisticated, but will do. Note that you need to test for `zerop' before using it, because if you call it with zero the iteration callback will not be called.
(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
Also note that for big numbers `ash' may become quite expensive, in which case you probably want to use 6502's variant.
Upvotes: 0
Reputation: 26539
Take a look at logbitp, which lets you access individual bits of an integer. For example,
(loop for i below (integer-length 109)
collect (if (logbitp i 109) 1 0))
=> (1 0 1 1 0 1 1)
Upvotes: 6
Reputation: 114529
If you want to process only "ones" then looping over all bits is not efficient if the ones are few. This is what I'd do in this case
(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))))
It uses the nice 2-complement facts that bit-anding a number and its opposite returns the least significant set bit and that bit-anding a number and one less than the number zeroes this least significant set bit.
Note that this processing works from the least significant set bit to the most significant (in your example you used the opposite ordering)
Upvotes: 6