unsigned-bit-shift-right

added
1.6

ns
clojure.core

type
function

(unsigned-bit-shift-right x n)

Bitwise shift right, without sign-extension.

                user=> (format "%016x" -1)
"ffffffffffffffff"

;; bit-shift-right sign extends most significant bit while right shifting.
user=> (format "%016x" (bit-shift-right -1 10))
"ffffffffffffffff"

;; unsigned-bit-shift-right fills most significant bits of result with 0.
;; No sign extension.
user=> (format "%016x" (unsigned-bit-shift-right -1 10))
"003fffffffffffff"

            
                ;; Warning: unsigned-bit-shift-right, like bit-shift-right, treats inputs as
;; type Long. Smaller types like byte, short, and int will not behave as such.
(format "0x%x" (byte -128))
; => "0x80"
(format "0x%x" (unsigned-bit-shift-right (byte -128) 1))
; => "0x7fffffffffffffc0"
(format "0x%x" (bit-shift-right (byte -128) 1))
; => "0xffffffffffffffc0"

; If you expected 0x40, you need to upcast your byte yourself, via bit-and,
; and only then shift:
(format "0x%x" (bit-shift-right (bit-and 0xff (byte -128)) 1))
; => "0x40"
            
                ;; Stein's Algorithm (Binary GCD)
;; https://en.wikipedia.org/wiki/Binary_GCD_algorithm


(defn gcd [a b]
  (cond
    (zero? a) b
    (zero? b) a
    (neg? a) (- a)
    (neg? b) (- b)
    (and (even? a) (even? b)) (* 2
                                 (gcd (unsigned-bit-shift-right a 1)
                                      (unsigned-bit-shift-right b 1)))
    (and (even? a) (odd? b)) (recur (unsigned-bit-shift-right a 1) b)
    (and (odd? a) (even? b)) (recur a (unsigned-bit-shift-right b 1))
    (and (odd? a) (odd? b)) (recur (unsigned-bit-shift-right
                                    (Math/abs (long (- a b))) ;; coerce to avoid reflection
                                    1) (min a b))))