JoelSanchez - 1 year ago 96
Javascript Question

# Implementing JavaScript's left shift operator in Clojure

I need to do a left shift operation that behaves the exact same way as JavaScript's. The problem is that this:

``````a << 16
``````

behaves like Clojure's "bit-shift-left" only if a <= 32767:

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

I noticed that, when doing "37431 << 16", JS does something completely different from Clojure at a binary level. While Clojure transforms 1001001000110111 into 10010010001101110000000000000000, JS transforms 1001001000110111 into 1101101110010010000000000000000:

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

I notice this is two's complement, and I notice that JS may be doing this because it cannot (for some reason) use more than 32 bits for this (all bit-level operations done on 32 bits, maybe?), so I wonder if I should apply two's complement to the number if it is above 32767. But then again, I'm a Clojure newbie so I'm not very sure on how to do this.

Firstly, `clojure.core/bit-shift-left` will treat its left input as a `long`. You can use `clojure.lang.Numbers/shiftLeftInt` to shift a number as an `int`:

``````(clojure.lang.Numbers/shiftLeftInt 567890 16)
;= -1437466624
``````

This matches the result you get in JavaScript. There's no wrapper around this static method in `clojure.core`, but you can provide your own.

Secondly, `(clojure.lang.Numbers/shiftLeftInt 37431 16)` evaluates to `-1841889280` in Clojure (1.8.0) and `37431 << 16` evaluates to the same number, `-1841889280`, in Node (4.4.5), so I don't think there's any problem there. You'll have to apply `>>> 0` to your number in JavaScript to get the expected bits in the string representation, though:

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

It's good to note that fishing out individual bits with `&` works fine without the `>>> 0` "unsigned cast":

``````> (37431 << 16) & (1 << 31)
-2147483648
> (37431 << 16) & (1 << 30)
0
> (37431 << 16) & (1 << 29)
0
> (37431 << 16) & (1 << 28)
268435456
``````

And you can compute both string representations in Clojure:

``````(Integer/toString (clojure.lang.Numbers/shiftLeftInt 37431 16) 2)
;= "-1101101110010010000000000000000"
(Integer/toBinaryString (clojure.lang.Numbers/shiftLeftInt 37431 16))
;= "10010010001101110000000000000000"
``````

Note that in Java bit shift operators take only the rightmost 5 or 6 bits (for `int`s and `long`s, respectively) of the right operand into account, so if you try shifting an `int` or `long` by more than 31/63 bits, you won't get the result you expect. `java.lang.BigInteger` has a `shiftLeft` method that does not have this limitation.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download