Was macht ~~ ("doppelte Tilde") in Javascript?

204

Ich habe heute eine Online-Bibliothek für Spielphysik ausgecheckt und bin auf den Operator ~~ gestoßen. Ich weiß, dass ein einzelnes ~ ein bitweises NICHT ist. Würde das ~~ zu einem NICHT eines NICHT machen, das den gleichen Wert zurückgeben würde, nicht wahr?

Shane Tomlinson
quelle

Antworten:

248

Es wird alles nach dem Dezimalpunkt entfernt, da die bitweisen Operatoren ihre Operanden implizit in vorzeichenbehaftete 32-Bit-Ganzzahlen konvertieren. Dies funktioniert unabhängig davon, ob die Operanden (Gleitkomma-) Zahlen oder Zeichenfolgen sind und das Ergebnis eine Zahl ist.

Mit anderen Worten, es ergibt sich:

function(x) {
  if(x < 0) return Math.ceil(x);
  else return Math.floor(x);
}

Nur wenn x zwischen - (2 31 ) und 2 31 - 1 liegt. Andernfalls tritt ein Überlauf auf und die Zahl wird "umbrochen".

Dies kann als nützlich angesehen werden, um das String-Argument einer Funktion in eine Zahl umzuwandeln, aber sowohl wegen der Möglichkeit eines Überlaufs als auch weil es für die Verwendung mit Nicht-Ganzzahlen falsch ist, würde ich es nicht so verwenden, außer für "Code Golf" ( dh sinnloses Abschneiden von Bytes aus dem Quellcode Ihres Programms auf Kosten der Lesbarkeit und Robustheit). Ich würde +xoder Number(x)stattdessen verwenden.


Wie das das NICHT des NICHT ist

Die Nummer -43.2 lautet zum Beispiel:

-43,2 10 = 11111111111111111111111111010101 2

als vorzeichenbehaftete 32-Bit-Binärzahl (Zweierkomplement). (JavaScript ignoriert, was nach dem Dezimalpunkt steht.) Das Invertieren der Bits ergibt:

NICHT -43 10 = 00000000000000000000000000101010 2 = 42 10

Wieder invertieren ergibt:

NICHT 42 10 = 11111111111111111111111111010101 2 = -43 10

Dies unterscheidet sich davon, Math.floor(-43.2)dass negative Zahlen gegen Null gerundet werden und nicht davon entfernt sind. (Die Floor-Funktion, die gleich -44 wäre, rundet immer auf die nächstniedrigere Ganzzahl ab, unabhängig davon, ob die Zahl positiv oder negativ ist.)

PleaseStand
quelle
6
Das heißt, es ~~ist eine Kurzform (und möglicherweise eine gute Lösung?), Um eine abgeschnittene Funktion zu erstellen , aber offensichtlich in Javascript .
Ruffin
4
JSLint wird sich über die Verwendung von beschweren ~~.
Richard Cook
1
Versuchen Sie Math.trunc ()
Xitalogy
30

Der erste ~ -Operator erzwingt den Operanden in eine Ganzzahl (möglicherweise nachdem der Wert in einen String oder einen Booleschen Wert gezwungen wurde) und invertiert dann die niedrigsten 31 Bits. Offiziell sind ECMAScript-Zahlen alle Gleitkommazahlen, aber einige Zahlen sind in der SpiderMonkey-Engine als 31-Bit-Ganzzahlen implementiert.

Sie können es verwenden, um ein 1-Element-Array in eine Ganzzahl umzuwandeln. Gleitkommawerte werden nach der C-Regel konvertiert, d. H. Abschneiden des Bruchteils.

Der zweite ~ -Operator invertiert dann die Bits zurück, sodass Sie wissen, dass Sie eine Ganzzahl haben. Dies ist nicht dasselbe wie das Erzwingen eines booleschen Werts in einer Bedingungsanweisung, da ein leeres Objekt {} als wahr ausgewertet wird, während ~~ {} als falsch ausgewertet wird.

js>~~"yes"
0
js>~~3
3
js>~~"yes"
0
js>~~false
0
js>~~""
0
js>~~true
1
js>~~"3"
3
js>~~{}
0
js>~~{a:2}
0
js>~~[2]
2
js>~~[2,3]
0
js>~~{toString: function() {return 4}}
4
js>~~NaN
0
js>~~[4.5]
4
js>~~5.6
5
js>~~-5.6
-5
Shanti
quelle
1
Danke für all die Beispiele hier, Shanti, es hat wirklich geholfen!
Shane Tomlinson
6
auch~~undefined // 0
Rampion
1
auch~~null // 0
chovy
Technisch haben Sie die falsche Reihenfolge. Der zweite ~macht das, was Sie beschrieben haben, der erste ~macht und umgekehrt. Der ~Operator ist ein unärer Operator und wird von rechts nach links ~~X~(~X)(~~)X
interpretiert. Das
20

In ECMAScript 6, das Äquivalents ~~ist Math.trunc :

Gibt den integralen Teil einer Zahl zurück, indem alle gebrochenen Ziffern entfernt werden. Es werden keine Zahlen gerundet.

Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN

Die Polyfüllung:

function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}
Gajus
quelle
6
Etwas überraschend ist ~~ schneller als Math.trunc, jsperf.com/math-trunc-vs-double-bitwise-not-operator . Allerdings dreht sich nicht alles um Geschwindigkeit; Lesbarkeit auch.
Gajus
3
Es gibt einen wichtigen Unterschied zwischen ~~ und Math.trunc: Wenn Sie eine Zeichenfolge oder NaN oder etwas anderes übergeben, das keine Zahl ist, gibt Math.trunc NaN zurück, und ~~ gibt in diesen Fällen immer eine Zahl zurück wird 0 zurückgeben.
Buzinas
Math.trunc ist geringfügig schneller als ~~ in Chrome 59+, nach jsperf.com/math-trunc-vs-double-bitwise-not-operator .
Jack Steam
7

Gegeben ~Nist -(N+1), ~~Nist dann -(-(N+1) + 1). Was offensichtlich zu einem ordentlichen Trick führt .

James Sumners
quelle
Ich muss nach unten zu Matts Kommentar scrollen, um ihn richtig zu verwenden;)
mplungjan
3

Nur eine kleine Warnung. Die anderen Antworten hier haben mich in Schwierigkeiten gebracht.

Die Absicht ist, alles nach dem Dezimalpunkt einer Gleitkommazahl zu entfernen, aber es gibt einige Eckfälle, die es zu einer Fehlergefahr machen. Ich würde empfehlen, ~~ zu vermeiden.

Erstens funktioniert ~~ bei sehr großen Zahlen nicht.

~~1000000000000 == -727279968

Alternativ können Sie verwenden Math.trunc()(wie Gajus erwähnt hat, Math.trunc()gibt den ganzzahligen Teil einer Gleitkommazahl zurück, ist jedoch nur in ECMAScript 6-kompatiblem JavaScript verfügbar). Sie können jederzeit Ihre eigenen Math.trunc()Umgebungen für Nicht-ECMAScript-6-Umgebungen erstellen, indem Sie Folgendes tun:

if(!Math.trunc){
    Math.trunc = function(value){
        return Math.sign(value) * Math.floor(Math.abs(value));
    }
}

Ich habe dazu einen Blog-Beitrag als Referenz geschrieben: http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technique-in.html

JSideris
quelle
1

Hier ist ein Beispiel dafür, wie dieser Operator effizient verwendet werden kann, wenn es sinnvoll ist, ihn zu verwenden:

leftOffset = -(~~$('html').css('padding-left').replace('px', '') + ~~$('body').css('margin-left').replace('px', '')),

Quelle:

Siehe Abschnitt Interaktion mit Punkten

Cssyphus
quelle
1

Konvertieren von Zeichenfolgen in Zahlen

console.log(~~-1);    // -1
console.log(~~0);     // 0
console.log(~~1);     // 1
console.log(~~"-1");  // -1
console.log(~~"0");   // 0
console.log(~~"1");   // 1
console.log(~~true);  // 1
console.log(~~false); // 0

~ -1 ist 0

if (~someStr.indexOf("a")) {
  // Found it
} else  {
  // Not Found
}

Quelle

Mike
quelle
1

Tilde (~) hat einen Algorithmus - (N + 1)

Zum Beispiel:

~0 = -(0+1) = -1
~5 = -(5+1) = -6
~-7 = -(-7+1) = 6

Doppelte Tilde ist - (- (N + 1) +1)

Beispielsweise:

~~5 = -(-(5+1)+1) = 5
~~-3 = -(-(-3+1)+1) = -3

Dreifache Tilde ist - (- (- (N + 1) +1) +1)

Beispielsweise:

~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4
CroMagnon
quelle