我需要执行一个左移操作,其行为方式与 JavaScript 的完全相同。问题是这样的:
a << 16
仅当 a <= 32767 时才表现得像 Clojure 的“bit-shift-left”:
// JS
32767 << 16 // 2147418112
32768 << 16 // -2147483648
567890 << 16 // -1437466624
;; CLJ
(bit-shift-left 32767 16) // 2147418112
(bit-shift-left 32768 16) // 2147483648
(bit-shift-left 567890 16) // 37217239040
我注意到,当执行“37431 << 16”时,JS 在二进制级别上执行的操作与 Clojure 完全不同。 Clojure 将 1001001000110111 转换为 10010010001101110000000000000000,而 JS 将 1001001000110111 转换为 1101101110010010000000000000000:
// CLJ, then JS
10 01001 00011 01110 00000 00000 00000
1 10110 11100 10010 00000 00000 00000
我注意到这是二进制补码,并且我注意到 JS 可能会这样做,因为它不能(出于某种原因)为此使用超过 32 位(所有位级操作都在 32 位上完成,也许?),所以我想知道如果数字高于 32767,我是否应该对数字应用二进制补码。但话又说回来,我是 Clojure 新手,所以我不太确定如何执行此操作。
最佳答案
首先, clojure.core/bit-shift-left
会将其左侧输入视为 long
。您可以使用 clojure.lang.Numbers/shiftLeftInt
将数字转换为 int
:
(clojure.lang.Numbers/shiftLeftInt 567890 16)
;= -1437466624
这与您在 JavaScript 中获得的结果匹配。 clojure.core
中没有围绕此静态方法的包装器,但您可以提供自己的包装器。
其次, (clojure.lang.Numbers/shiftLeftInt 37431 16)
在 Clojure (1.8.0) 中计算为 -1841889280
,而 37431 << 16
在 Node (4.4.5) 中计算为相同的数字 -1841889280
,所以我认为那里没有任何问题。不过,您必须在 JavaScript 中将 >>> 0
应用于您的数字,才能获得字符串表示形式中的预期位:
// Node 4.4.5
> ((37431 << 16) >>> 0).toString(2)
'10010010001101110000000000000000'
值得注意的是,在没有 &
“无符号转换”的情况下,使用 >>> 0
找出各个位也可以正常工作:
> (37431 << 16) & (1 << 31)
-2147483648
> (37431 << 16) & (1 << 30)
0
> (37431 << 16) & (1 << 29)
0
> (37431 << 16) & (1 << 28)
268435456
您可以在 Clojure 中计算这两种字符串表示形式:
(Integer/toString (clojure.lang.Numbers/shiftLeftInt 37431 16) 2)
;= "-1101101110010010000000000000000"
(Integer/toBinaryString (clojure.lang.Numbers/shiftLeftInt 37431 16))
;= "10010010001101110000000000000000"
请注意,在 Java 中,移位运算符仅考虑右操作数的最右边 5 或 6 位(分别用于 int
和 long
),因此,如果您尝试将 int
或 long
移位超过 31/63位,您将不会得到您期望的结果。 java.lang.BigInteger
有一个 shiftLeft
方法没有此限制。
关于javascript - 在 Clojure 中实现 JavaScript 的左移运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38381719/