clojure - Right-shifting 32-bit ints -
clojure's bit-shift operations seem return 64-bit long
results, 32-bit int
arguments. not substantial problem bit-shift-left
:
user=> (format "%08x" (unchecked-int (bit-shift-left (unchecked-int 0x12345678) 4))) "23456780" user=> (format "%08x" (unchecked-int (bit-shift-left (unchecked-int 0xf2345678) 4))) "23456780"
however, becomes problem unsigned right-shifting of negative numbers:
user=> (format "%08x" (unchecked-int (unsigned-bit-shift-right (unchecked-int 0xf2345678) 4))) "ff234567"
the correct answer, of course, 0f234567
.
what efficient way implement 32-bit unsigned right-shifting in clojure?
this can accomplished calling int clojure.lang.numbers.unsignedshiftrightint(int, int)
method uses >>>
on int
arguments, returning int
. it's not exposed function anywhere, have intrinsic implementation (equivalent >>>
in java) , can either call directly or wrap in own inlinable function:
(defn unsigned-bit-shift-right-int {:inline (fn [x n] `(clojure.lang.numbers/unsignedshiftrightint ~x ~n))} [x n] (clojure.lang.numbers/unsignedshiftrightint x n))
this returns correct value whether gets inlined or not, of course you'd want inlined. it's make sure arguments primitive int
s intrinsic can kick in.
here's compiles in clojure 1.8 in 2 possible cases inlined (the non-inlined case regular function call, nothing see there):
inlined primitive arguments:
abusing count
little bit illustrate point. note iushr
instruction.
clojure
deftype
:(deftype foo [^int x ^int y] clojure.lang.counted (count [this] (unsigned-bit-shift-right-int x y)))
bytecode:
// method descriptor #61 ()i // stack: 2, locals: 1 public int count(); 0 aload_0 [this] 1 getfield user.foo.x : int [19] 4 aload_0 [this] 5 getfield user.foo.y : int [21] 8 iushr 9 ireturn line numbers: [pc: 0, line: 1] [pc: 8, line: 4] local variable table: [pc: 0, pc: 9] local: index: 0 type: user.foo
inlined non-primitive arguments:
note invokestatic clojure.lang.numbers.unsignedshiftright…
instruction.
clojure expression:
#(format "%08x" (clojure.lang.numbers/unsignedshiftrightint (unchecked-int 0xf2345678) 4))
bytecode:
// method descriptor #11 ()ljava/lang/object; // stack: 5, locals: 1 public java.lang.object invoke(); 0 getstatic user$eval16141$fn__16142.const__0 : clojure.lang.var [15] 3 invokevirtual clojure.lang.var.getrawroot() : java.lang.object [20] 6 checkcast clojure.lang.ifn [22] 9 ldc <string "%08x"> [24] 11 ldc2_w <long 4063516280> [25] 14 l2i 15 ldc2_w <long 4> [27] 18 invokestatic clojure.lang.rt.intcast(long) : int [34] 21 invokestatic clojure.lang.numbers.unsignedshiftrightint(int, int) : int [40] 24 invokestatic java.lang.integer.valueof(int) : java.lang.integer [46] 27 invokeinterface clojure.lang.ifn.invoke(java.lang.object, java.lang.object) : java.lang.object [49] [nargs: 3] 32 areturn line numbers: [pc: 0, line: 1] [pc: 6, line: 1] [pc: 14, line: 1] [pc: 21, line: 1] [pc: 27, line: 1] local variable table: [pc: 0, pc: 32] local: index: 0 type: java.lang.object
Comments
Post a Comment