【问题标题】:Implementing JavaScript's left shift operator in Clojure在 Clojure 中实现 JavaScript 的左移运算符
【发布时间】:2016-11-17 19:32:55
【问题描述】:

我需要执行与 JavaScript 完全相同的左移操作。问题在于:

a << 16

只有当

// 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

// CLJ, then JS
10 01001 00011 01110 00000 00000 00000
 1 10110 11100 10010 00000 00000 00000

我注意到这是二进制补码,并且我注意到 JS 可能会这样做,因为它不能(出于某种原因)为此使用超过 32 位(可能所有位级操作都在 32 位上完成?),所以我想知道如果数字高于 32767,我是否应该对数字应用二进制补码。但话说回来,我是 Clojure 新手,所以我不太确定如何做到这一点。

【问题讨论】:

    标签: javascript clojure bit-manipulation


    【解决方案1】:

    首先,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) 中计算为 -184188928037431 &lt;&lt; 16 在 Node (4.4.5) 中计算为相同的数字 -1841889280,所以我认为没有那里的问题。不过,您必须在 JavaScript 中将 &gt;&gt;&gt; 0 应用于您的号码,才能获得字符串表示中的预期位:

    // Node 4.4.5
    > ((37431 << 16) >>> 0).toString(2)
    '10010010001101110000000000000000'
    

    需要注意的是,在没有 &gt;&gt;&gt; 0“无符号转换”的情况下,使用 &amp; 钓出单个位也可以正常工作:

    > (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 位(分别为 ints 和 longs),因此如果您尝试移位 int 或 @ 987654340@ 超过 31/63 位,你不会得到你期望的结果。 java.lang.BigInteger 有一个 shiftLeft 方法,没有这个限制。

    【讨论】:

      猜你喜欢
      • 2014-08-02
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-03
      相关资源
      最近更新 更多