2016-07-14 10 views
2

Ich muss eine Links-Shift-Operation ausführen, die sich genau wie JavaScript verhält. Das Problem ist, dass dies:Implementieren des Linksverschiebungs-Operators von JavaScript in Clojure

a << 16 

verhält sich wie Clojure der "Bit-Shift-links" nur dann, wenn ein < = 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 

Ich bemerkte, dass, wenn dabei "37431 < < 16", JS macht etwas völlig anderes als Clojure auf einer binären Ebene. Während Clojure 1001001000110111 in 10010010001101110000000000000000 verwandelt, verwandelt JS 1001001000110111 in 1101101110010010000000000000000:

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

Ich bemerke das Komplement ist zwei, und ich merke, dass JS dies tun kann, weil es nicht (aus irgendeinem Grund) mehr als 32 Bits für verwenden Dies (alle Bit-Level-Operationen auf 32 Bit, vielleicht?), so frage ich mich, ob ich Zweierkomplement auf die Zahl anwenden sollte, wenn es über 32767 ist. Aber andererseits bin ich ein Clojure-Neuling, also bin ich nicht sehr sicher, wie man das macht.

Antwort

2

Zuerst behandelt clojure.core/bit-shift-left seinen linken Eingang als long. Sie können clojure.lang.Numbers/shiftLeftInt verwenden, um eine Zahl als int zu verschieben:

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

Dies ist das Ergebnis Sie in JavaScript erhalten einstimmt. Es gibt keinen Wrapper um diese statische Methode in clojure.core, aber Sie können Ihre eigenen bereitstellen.

Zweitens wertet (clojure.lang.Numbers/shiftLeftInt 37431 16)--1841889280 in Clojure (1.8.0) und 37431 << 16 wertet auf die gleiche Anzahl, -1841889280, in Knoten (4.4.5), so dass ich glaube nicht, dass es dort ein Problem. Sie werden >>> 0 auf Ihre Zahl in JavaScript anwenden müssen, um die erwarteten Bits in der String-Darstellung zu erhalten, aber:

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

Es ist gut, dass einzelne Bits Fischen aus zu beachten, mit & ohne >>> 0 „unsigned Besetzung funktioniert gut „:

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

Und Sie können beide Stringdarstellungen in Clojure berechnen:

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

Beachten Sie, dass in Java Bitverschiebungsoperatoren nur die rechten 5 oder 6 Bits (für int s bzw. long s) des rechten Operanden berücksichtigen. Wenn Sie also versuchen, eine int oder long um mehr als 31/63 Bits zu verschieben wird nicht das Ergebnis erhalten, das Sie erwarten. java.lang.BigInteger hat eine shiftLeft Methode, die diese Einschränkung nicht aufweist.

Verwandte Themen