(bit-shift-right x n)
Bitwise shift right
;; Convert number into list of bits:
(defn bits [n s]
(take s
(map
(fn [i] (bit-and 0x01 i))
(iterate
(fn [i] (bit-shift-right i 1))
n))))
;; #'user/bits
(map (fn [n] (bits n 3)) (range 8))
;;=> ((0 0 0) (1 0 0) (0 1 0) (1 1 0) (0 0 1) (1 0 1) (0 1 1) (1 1 1))
(bit-shift-right 2r1101 0) ;;=> 13
(bit-shift-right 2r1101 1) ;;=> 6
(bit-shift-right 2r1101 2) ;;=> 3
(bit-shift-right 2r1101 3) ;;=> 1
(bit-shift-right 2r1101 4) ;;=> 0
;; Warning: bit-shift-right upcasts arguments to Long and returns Long
(format "0x%x" (byte -128))
; => "0x80"
(format "0x%x" (bit-shift-right (byte -128) 1)) ; You'd expect 0x40?
; => "0xffffffffffffffc0"
; You'd expect 0x40, but (byte -128) was converted to (long -128) and then
; right-shifted, with the negative sign bit of 1 propagated.
; This can't be avoided by using unsigned-bit-shift-right:
(format "0x%x" (unsigned-bit-shift-right (byte -128) 1))
; => "0x7fffffffffffffc0"
; If you want unsigned "byte" operations, upcast the byte yourself via bit-and:
(format "0x%x" (bit-shift-right (bit-and 0xff (byte -128)) 1))
; => "0x40"
; This works because the output of bit-and is always Long:
(type (bit-and 0xff (byte -128)))
; => java.lang.Long
; Note that bit-and returns Long even if both arguments are smaller:
(type (bit-and (short 0xff) (byte -128)))
; => java.lang.Long
;; floating point bit-shifting
;; thanks to Gary Fredericks: https://github.com/gfredericks/doubles
(defn bit-shift-double [x shifts]
(let [x-long (Double/doubleToRawLongBits x)]
(Double/longBitsToDouble
(bit-or (bit-and 1 x-long)
(bit-shift-left (- (bit-shift-right x-long 52) shifts) 52)
(bit-and 0xfffffffffffff x-long)))))