I got a octet (byte) and a number of relevant-bits and I want to keep the first n (relevant-bits) of that given byte and set the remaining bits to zero.
E.g.
The number 217 where the first 4 bits are relevant would convert to 208
0 0
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+ ==> +-+-+-+-+-+-+-+
1 1 0 1 1 0 0 1 1 1 0 1 0 0 0 0
The number 255 where the first 8 (or greater) bits are relevant would not change at all
0 0
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+ ==> +-+-+-+-+-+-+-+
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
I wrote this function to solve the problem
(defun list-of-bits (integer)
(let ((bits '()))
(dotimes (position (integer-length integer) bits)
(push (ldb (byte 1 position) integer) bits))))
(defun calculate-octet (byte rel-bits)
(if (< rel-bits 8)
(parse-integer
(FORMAT nil "~{~a~}"
(replace (list-of-bits byte)
'(0 0 0 0 0 0 0 0)
:start1 rel-bits
:end1 8
:start2 0
:end2 rel-bits))
:radix 2)
byte))
But this solution seems bad for two reasons
it splits the integer into a list before processing it
it prints the list into a string which is again parsed
I know that common-lisp provides functions to directly access the bits and bytes (ldb,logbitp) but I could not figure out a way to use them for my problem.
Is there a way to solve the problem more efficient (or at least more elegant)?
CL-USER 6 > (mask-field (byte 4 4) 217)
208
Note also that it does not mask the field of the original number, but returns a new number with the bit field masked.
There are already three answers, so I may as well add another two:
No one suggested DPB yet. Always nice with a nod to the PDP-10.
(defun calculate-octet (byte bits)
(dpb 0 (byte bits bits) byte))
Again with the LOGAND.
(defun calculate-octet (byte bits)
(logand byte (ash -1 (- 8 bits))))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With