2015-12-18 4 views
48

Was bedeutet 'x < < ~ y' in JavaScript?Was bedeutet "x << ~ y" in JavaScript?

Ich verstehe, dass die bitweise SHIFT Operation tut dies:

x << y AS x * 2y

Und ein ~ Tilde Operator tut:

~x AS -(x+1) 

Also, ich nehme an, die folgenden:

5 << ~3 AS 5 * 2-4 or 5 * Math.pow(2, -4)

Es sollte in 0.3125 resultieren.

Aber wenn ich 5 << ~3 ausführen, ergibt es 1342177280.

Was ist eine Schritt-für-Schritt-Erklärung? Wie und warum führt diese Kombination von Operationen zu 1342177280 anstelle von 0.3125?

(Diese Frage ist ähnlich   Überlauf Frage What are bitwise operators? über die bitweise SHIFT Operator zu stapeln.)

+5

Wie könnte eine Bit-Shift-Operation ein gebrochenes Ergebnis wie 0,3125 ergeben? – edc65

+0

@ edc65 Das ist die Annahme, dass die Antwort auf dem grundlegenden Lernen von 'XOR' und Tilde' ~ 'basiert. Ich habe absolut keine Ahnung, wie das eigentlich funktionieren soll. – choz

+9

nach '! -' und '<< ~' was kommt als nächstes? Ich soll posten "Was macht der'^< dhein

Antwort

50

x << -n gleich x << (32 - n)
~3 == -4 so
5 << ~3 === 5 << (32 - 4) === 5 << 28 die 1,342,177,280

korrekt X < < -n ist nicht dasselbe wie X < < (sein 32 - n) ... in der Tat ist es einfacher und komplizierter ... der gültige Bereich eines Bit-Shift-Operators ist 0 bis 31 ... der RHS in einem Bit-Shift-Operator wird zuerst in eine vorzeichenlose 32-Bit-Integer umgewandelt, th en mit 31 (hex 1f) maskierte (binär 11111)

    3 = 00000000000000000000000000000011 
        ~3 = 11111111111111111111111111111100 
     0x1f (the mask) 00000000000000000000000000011111 
         -------------------------------- 
      ~3 & 0x1f 00000000000000000000000000011100 = 28 

, wenn die Größe als 32 weniger ist, dann ist es genau das gleiche wie das, was ich oben geschrieben, obwohl

Bit-Operationen mit 32-Bit-Integer arbeiten . Negative Bit-Verschiebungen bedeutungslos sind, so werden in positive ganze Zahlen sind 32-Bit gewickelt

Wie die << operator arbeitet

rhs auf eine unsigned 32-Bit-Integer-Wert umgesetzt wird - wie hier erklärt ToUInt32

ToUint32 nimmt im Grunde eine Reihe und kehrt die Zahl modulo 2^32

+2

Wie erhalten Sie den Hinweis, dass '-n' gleich' (32 - n) 'ist? Ich bezweifle nicht die Tatsache, dass dies ist Aber ich bin nur neugierig, da ich keinen finden konnte – choz

+6

@choz Das geht eigentlich bis zur Computerarchitektur zurück, weil die meisten Computeranweisungen 5 Bits zum Speichern des Verschiebungsbetrags (* mindestens Für MIPS *). Speziell diese Bits sind nicht signiert binär. –

+0

Es ist nicht 32-n. Es ist nur die am wenigsten signifikanten 5 Bits, das ist "n & 31" (siehe zitierten Verweis auf Operator <<, 12.8.3.11 subpoint 11) Wenn * n * negativ ist, dann gilt: 32 + n' == 'n & 31' – edc65

7

~x wird die Bit-Darstellung Ihres x-Wert umgekehrt (32 Bit signed Wert mit Zweierkomplement).

x << y ist der linke Shift-Operator (hier links). Ihre mathematische Interpretation ist richtig :)

Sie können mehr über bitweise Operationen hier lesen: bitwise operators in Javascript

6

5 << ~3 gibt das gleiche Ergebnis wie 5 << -4, Sie haben Recht.

Wichtig: Verschiebung x < < y wirklich Ergebnisse in x * 2 y, aber es ist nicht eine direkte Nutzung, es ist nur eine nützliche Nebenwirkung. Wenn Sie einen negativen y haben, funktioniert es nicht auf die gleiche Weise.

+0

Wie soll das mit negativem Wert BTW funktionieren? Es tut mir leid, dass ich die Bitdarstellung von irgendetwas nicht wirklich verstehe. – choz

+1

*, wenn du ein negatives y hast, funktioniert es nicht auf die gleiche Weise * also hast du eigentlich keine Antwort auf die eigentliche Frage –

20

Der Operator ~ dreht die Bits des Elements, während << eine bitweise Verschiebung nach links ist. Hier geschieht Schritt für Schritt, was binär passiert. Man beachte, dass die linke Bit ist 1 eine negative Zahl bezeichnet wird, ist dieses Format twos compliment:

3   // (00000000000000000000000000000011 => +3 in decimal) 
// ~ flips the bits 
~3  // (11111111111111111111111111111100 => -4 in decimal) 
// The number 5 (..00101) shifted by left by -4 (-4 unsigned -> 28) 
5   // (00000000000000000000000000000101 => +5 in decimal) 
5 << -4 // (01010000000000000000000000000000 => +1342177280 in decimal) 

In der letzten Zeile werden die Bits verschoben und „gedreht“ auf die andere Seite, auf eine große positive Zahl führenden . Tatsächlich ist das Verschieben um eine negative Zahl einer bitweisen Drehung ähnlich (übergelaufene Bits werden auf die andere Seite gedreht), wo das Verschieben durch positive Zahlen kein solches Verhalten hat. Der Nachteil ist, dass die nicht gedrehten Bits nicht berücksichtigt werden. Im Wesentlichen bedeutet das, dass 5 << -4 dasselbe ist wie 5 << (32 - 4), dass eher die Rotation tatsächlich eine große Verschiebung ist.

Die Begründung dafür ist, weil Bitverschiebungen nur ein 5-Bit unsigned Integer sind. Also die Binärzahl in zwei Komplement -4 (11100) unsigned wäre 28.

+0

@JaromandaX Ach du bist richtig, es ist binäre 5 um -4 verschoben. Geben Sie mir eine Sekunde, das erklärt, indem ich scheint, bin ich um 1. –

+0

Danke für Ihre Antwort spencer. Ich verwende einen Online-Binärkonverter, der '0000011111111111111111111111111111'' 0x07FFFFFF' ist, was sich als '134217727' ergibt. Mache ich hier etwas falsch? – choz

+0

@choz Das war ein Durcheinander von mir, ich las den letzten Ausdruck in einer falschen Reihenfolge und bekam zufällig eine sehr enge Nummer. Ich habe meine Antwort aktualisiert. –

9

Ihre Analyse ist korrekt, außer dass Sie ~ 3 (11100) (das Bit-Komplement von 3 (00011)) nicht als -4, sondern als unsigned interpretieren negativ) 5-Bit-Ganzzahl, nämlich 28 = 16 + 8 + 4 (11100).

Dies ist in dem ECMAScript standard (NB in den meisten modernen Maschinen, positive und negative ganze Zahlen im Speicher mit two's complement Darstellung dargestellt werden) erklärt:

12.8.3 Der Linkse Shift-Operator (< <)

HINWEIS Führt für den linken Operanden eine bitweise Verschiebung nach links um den vom rechten Operanden angegebenen Wert aus.

12.8.3.1 Runtime Semantics: Evaluation

ShiftExpression: ShiftExpression < < AdditiveExpression

  1. Let Lref das Ergebnis der Auswertung ShiftExpression sein.
  2. Lassen Sie lval GetValue (lref) sein.
  3. ReturnIfAbrupt (lval).
  4. Lassen Sie Rref das Ergebnis der Auswertung von AdditiveExpression sein.
  5. Sei rval GetValue (rref).
  6. ReturnIfAbrupt (rval).
  7. Lassen Sie lnum ToInt32 (lval) sein.
  8. ReturnIfAbrupt (lnum).
  9. Lassen Sie rnum ToUint32 (rval) sein.
  10. ReturnIfAbrupt (rnum).
  11. Lassen Sie ShiftCount das Ergebnis der Ausblendung aller außer den am wenigsten signifikanten 5 Bits von rnum sein, das heißt, berechnen Sie Rnum & 0x1F.
  12. Geben Sie das Ergebnis der linken Verschiebung von lnum durch shiftCount Bits zurück. Das Ergebnis ist eine 32-Bit-Ganzzahl mit Vorzeichen.