右移 32 位整数
Right-shifting 32-bit ints
Clojure 的移位操作似乎都是 return 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 位无符号右移的最有效方法是什么?
这可以通过调用 int clojure.lang.Numbers.unsignedShiftRightInt(int, int)
方法来完成,该方法在 int
个参数上使用 >>>
,返回 int
。它目前没有在任何地方作为函数公开,但它确实有一个内部实现(相当于 Java 中的 >>>
),您可以直接调用它或包装在您自己的可内联函数中:
(defn unsigned-bit-shift-right-int
{:inline (fn [x n] `(clojure.lang.Numbers/unsignedShiftRightInt ~x ~n))}
[x n]
(clojure.lang.Numbers/unsignedShiftRightInt x n))
这个 returns 无论是否被内联都是正确的值,但当然通常您希望它被内联。确保参数实际上是原始的 int
s 也很好,这样内部函数就可以启动。
这是它在 Clojure 1.8 中编译成的两种可能的内联情况(non-inlined 情况是常规函数调用,没有什么可看的):
内联原始参数:
滥用 count
只是为了说明这一点。注意 iushr
指令。
Clojure deftype
:
(deftype Foo [^int x ^int y]
clojure.lang.Counted
(count [this]
(unsigned-bit-shift-right-int x y)))
字节码:
// 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
内联 non-primitive 个参数:
注意 invokestatic clojure.lang.Numbers.unsignedShiftRight…
指令。
Clojure 表达式:
#(format "%08x"
(clojure.lang.Numbers/unsignedShiftRightInt (unchecked-int 0xf2345678) 4))
字节码:
// 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: this index: 0 type: java.lang.Object
Clojure 的移位操作似乎都是 return 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 位无符号右移的最有效方法是什么?
这可以通过调用 int clojure.lang.Numbers.unsignedShiftRightInt(int, int)
方法来完成,该方法在 int
个参数上使用 >>>
,返回 int
。它目前没有在任何地方作为函数公开,但它确实有一个内部实现(相当于 Java 中的 >>>
),您可以直接调用它或包装在您自己的可内联函数中:
(defn unsigned-bit-shift-right-int
{:inline (fn [x n] `(clojure.lang.Numbers/unsignedShiftRightInt ~x ~n))}
[x n]
(clojure.lang.Numbers/unsignedShiftRightInt x n))
这个 returns 无论是否被内联都是正确的值,但当然通常您希望它被内联。确保参数实际上是原始的 int
s 也很好,这样内部函数就可以启动。
这是它在 Clojure 1.8 中编译成的两种可能的内联情况(non-inlined 情况是常规函数调用,没有什么可看的):
内联原始参数:
滥用 count
只是为了说明这一点。注意 iushr
指令。
Clojure
deftype
:(deftype Foo [^int x ^int y] clojure.lang.Counted (count [this] (unsigned-bit-shift-right-int x y)))
字节码:
// 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
内联 non-primitive 个参数:
注意 invokestatic clojure.lang.Numbers.unsignedShiftRight…
指令。
Clojure 表达式:
#(format "%08x" (clojure.lang.Numbers/unsignedShiftRightInt (unchecked-int 0xf2345678) 4))
字节码:
// 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: this index: 0 type: java.lang.Object