Clojure's bit-shift operations all seem to return 64-bit long results, even for 32-bit int arguments. This is not a substantial problem for 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, this becomes a problem for 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, would be 0f234567.
What is the most efficient way to implement 32-bit unsigned right-shifting in Clojure?
This can be accomplished by calling the
int clojure.lang.Numbers.unsignedShiftRightInt(int, int)method which uses>>>onintarguments, returningint. It's not currently exposed as a function anywhere, but it does have an intrinsic implementation (equivalent to>>>in Java) and you can either call it directly or wrap in your own inlinable function:This returns the correct value whether it gets inlined or not, but of course generally you'd want it to be inlined. It's also good to make sure that the arguments are actually primitive
ints so that the intrinsic can kick in.Here's what it compiles to in Clojure 1.8 in the two possible cases where it does get inlined (the non-inlined case is a regular function call, nothing to see there):
Inlined with primitive arguments:
Abusing
counta little bit just to illustrate the point. Note theiushrinstruction.Clojure
deftype:Bytecode:
Inlined with non-primitive arguments:
Note the
invokestatic clojure.lang.Numbers.unsignedShiftRight…instruction.Clojure expression:
Bytecode: