bit-shift-right

added
1.0

ns
clojure.core

type
function

(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)))))