我需要做一个左移操作,其行为与JavaScript完全相同。问题是:
a << 16
只有当&lt; = 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&lt;&lt; 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新手,所以我不太清楚如何做到这一点。
答案 0 :(得分:2)
首先,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'
值得注意的是,在没有&
&#34;无符号演员&#34;
>>> 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
s),因此如果您尝试移位{ {1}}或int
超过31/63位,您无法获得预期的结果。 long
有java.lang.BigInteger
方法,没有此限制。