右移32位整数

时间:2016-01-21 02:07:02

标签: clojure bit-shift signedness

Clojure的位移操作似乎都返回64位long结果,即使对于32位int参数也是如此。对于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"

但是,这会成为unsigned right-shifting负数的问题:

user=> (format "%08x" (unchecked-int (unsigned-bit-shift-right (unchecked-int 0xf2345678) 4)))
"ff234567"

当然,正确的答案是0f234567

在Clojure中实现32位无符号右移的最有效方法是什么?

1 个答案:

答案 0 :(得分:5)

这可以通过调用在int clojure.lang.Numbers.unsignedShiftRightInt(int, int)个参数上使用>>>的{​​{1}}方法,返回int来实现。它目前在任何地方都没有作为函数公开,但它确实有一个内部实现(相当于Java中的int),你可以直接调用它或者包装你自己的inlinable函数:

>>>

这会返回正确的值,无论它是否被内联,但当然通常你希望它被内联。确保参数实际上是原始(defn unsigned-bit-shift-right-int {:inline (fn [x n] `(clojure.lang.Numbers/unsignedShiftRightInt ~x ~n))} [x n] (clojure.lang.Numbers/unsignedShiftRightInt x n)) 以便内在函数可以启动也很好。

这里是它在Clojure 1.8中编译的内容,在两种可能的情况下它被内联(非内联案例是常规函数调用,没有什么可看的):

内联原始参数:

仅仅为了说明这一点而滥用int。请注意count指令。

  1. Clojure iushr

    deftype
  2. 字节码:

    (deftype Foo [^int x ^int y]
      clojure.lang.Counted
      (count [this]
        (unsigned-bit-shift-right-int x y)))
    
  3. 内联非原始参数:

    请注意// 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: this index: 0 type: user.Foo 指令。

    1. Clojure表达:

      invokestatic clojure.lang.Numbers.unsignedShiftRight…
    2. 字节码:

      #(format "%08x"
         (clojure.lang.Numbers/unsignedShiftRightInt (unchecked-int 0xf2345678) 4))