Frage mich, ob es nicht triviale Möglichkeiten gibt, das Vorzeichen einer Zahl zu finden ( Signum-Funktion )?
Kann kürzer / schneller / eleganter sein als die offensichtliche
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
Kurze Antwort!
Verwenden Sie dies und Sie werden sicher und schnell sein (Quelle: moz )
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
Sie können an Leistung und Typ-Nötigung Vergleich aussehen wollen Geige
Lange Zeit ist vergangen. Weiter ist vor allem aus historischen Gründen.
Ergebnisse
Im Moment haben wir diese Lösungen:
1. Offensichtlich und schnell
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. Modifikation von kbec - ein Typ weniger, leistungsfähiger, kürzer [am schnellsten]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
Vorsicht: sign("0") -> 1
2. Elegant, kurz, nicht so schnell [am langsamsten]
function sign(x) { return x && x / Math.abs(x); }
Vorsicht : sign(+-Infinity) -> NaN
,sign("0") -> NaN
Da Infinity
es sich bei JS um eine legale Nummer handelt, scheint diese Lösung nicht vollständig korrekt zu sein.
3. Die Kunst ... aber sehr langsam [am langsamsten]
function sign(x) { return (x > 0) - (x < 0); }
4. Verwenden Sie Bit-Shift
schnell, abersign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Typ-safe [megafast]
! Es scheint, als würden Browser (insbesondere Chrome v8) einige magische Optimierungen vornehmen, und diese Lösung ist viel leistungsfähiger als andere, selbst als (1.1), obwohl sie zwei zusätzliche Vorgänge enthält und logischerweise niemals schneller sein kann.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
Werkzeuge
- jsperf-Leistungstests ;
- Geige - Typ-Cast-Tests;
Verbesserungen sind willkommen!
[Offtopic] Akzeptierte Antwort
Andrey Tarantsov - +100 für die Kunst, aber leider ist es ungefähr 5 mal langsamer als der offensichtliche Ansatz
Frédéric Hamidi - irgendwie die am besten bewertete Antwort (für die Zeit des Schreibens) und es ist ein bisschen cool, aber es ist definitiv nicht so, wie Dinge gemacht werden sollten, imho. Außerdem werden Infinity-Zahlen, die auch Zahlen sind, nicht richtig verarbeitet.
kbec - ist eine Verbesserung der offensichtlichen Lösung. Nicht so revolutionär, aber zusammengenommen halte ich diesen Ansatz für den besten. Stimmen Sie für ihn :)
quelle
0
ein Sonderfall isttest everything
Version ausführen , weigert sich Safe natürlich, die speziellen Werte zu testen, sodass sie schneller sind! Versuchen Sieonly integers
stattdessen , den Test auszuführen. Außerdem macht JSPerf nur seinen Job, es geht nicht darum, ihn zu mögen. :)typeof x === "number"
die Leistung etwas magischer wird. Bitte machen Sie mehr Läufe, insbesondere FF, Opera und IE, um es klar zu machen.Math.sign()
(0 === 0, nicht so schnell wie "Sicher") hinzugefügt, der in FF25 erschien und in Chrom erscheint.Antworten:
Elegantere Version der schnellen Lösung:
quelle
var sign = (number)? ((number < 0)? -1 : 1 ) : 0
Math.sign(number)
Das Teilen der Zahl durch ihren absoluten Wert gibt auch ihr Vorzeichen. Die Verwendung des logischen UND-Kurzschlussoperators ermöglicht es uns, Sonderfälle zu erstellen,
0
damit wir uns nicht dadurch teilen:quelle
var sign = number && number / Math.abs(number);
für den Fall wollennumber = 0
0
muss speziell behandelt werden. Antwort entsprechend aktualisiert. Danke :)Die gesuchte Funktion heißt signum und lässt sich am besten implementieren:
quelle
Sollte dies nicht die vorzeichenbehafteten Nullen von JavaScript (ECMAScript) unterstützen? Es scheint zu funktionieren, wenn in der Funktion „Megafast“ eher x als 0 zurückgegeben wird:
Dies macht es kompatibel mit einem Entwurf von ECMAScript's Math.sign ( MDN ):
quelle
Für Leute, die interessiert sind, was mit den neuesten Browsern los ist, gibt es in der ES6-Version eine native Math.sign- Methode. Sie können den Support hier überprüfen .
Grundsätzlich kehrt es zurück
-1
,1
,0
oderNaN
quelle
Superschnell, wenn Sie Infinity nicht benötigen und wissen, dass die Zahl eine Ganzzahl ist, die in der Quelle openjdk-7 enthalten ist:
java.lang.Integer.signum()
quelle
Ich dachte, ich würde das nur zum Spaß hinzufügen:
0 und NaN geben -1 zurück. Funktioniert
gut bei +/- Unendlich
quelle
Eine Lösung, die für alle Zahlen sowie für
0
und-0
sowieInfinity
und funktioniert-Infinity
, ist:Weitere Informationen finden Sie in der Frage " Sind +0 und -0 gleich? ".
Achtung: Keine dieser Antworten, einschließlich der jetzt Standard
Math.sign
werden die Arbeiten an dem Fall0
vs-0
. Dies ist möglicherweise kein Problem für Sie, aber in bestimmten physischen Implementierungen kann es von Bedeutung sein.quelle
Sie können die Zahl bitverschieben und das höchstwertige Bit (MSB) überprüfen. Wenn das MSB eine 1 ist, ist die Zahl negativ. Wenn es 0 ist, ist die Zahl positiv (oder 0).
quelle
var sign = number < 0 : 1 : 0
n & 0x80000000
eine Bitmaske verwenden. Wie für die Konvertierung in 0,1, -1:n && (n & 0x80000000 ? -1 : 1)
-5e32
und es brach.ToInt32
. Wenn Sie dort lesen (Abschnitt 9.5), gibt es einen Modul, der den Wert der Zahlen beeinflusst, da der Bereich einer 32-Bit-Ganzzahl kleiner ist als der Bereich des Typs js Number. Für diese Werte oder die Unendlichkeiten funktioniert es also nicht. Die Antwort gefällt mir trotzdem.Ich wollte gerade die gleiche Frage stellen, kam aber zu einer Lösung, bevor ich mit dem Schreiben fertig war. Ich sah, dass diese Frage bereits vorhanden war, sah diese Lösung aber nicht.
(n >> 31) + (n > 0)
Es scheint jedoch schneller zu sein, wenn ein Ternär hinzugefügt wird
(n >> 31) + (n>0?1:0)
quelle
Sehr ähnlich zu Martijns Antwort ist
Ich finde es besser lesbar. Außerdem (oder, abhängig von Ihrer Sichtweise), werden auch Dinge erfasst, die als Zahl interpretiert werden können. zB kehrt es zurück,
-1
wenn es präsentiert wird'-5'
.quelle
Ich sehe keinen praktischen Grund für die Rückgabe von -0 und 0,
Math.sign
daher lautet meine Version:quelle
Ich kenne folgende Methoden:
Math.sign (n)
var s = Math.sign(n)
Dies ist die native Funktion, die jedoch aufgrund des Overheads eines Funktionsaufrufs am langsamsten ist. Es behandelt jedoch 'NaN', wobei die anderen unten möglicherweise nur 0 annehmen (dh Math.sign ('abc') ist NaN).
((n> 0) - (n <0))
var s = ((n>0) - (n<0));
In diesem Fall kann nur die linke oder rechte Seite eine 1 sein, basierend auf dem Vorzeichen. Dies führt entweder zu
1-0
(1),0-1
(-1) oder0-0
(0).Die Geschwindigkeit dieses einen scheint Hals an Hals mit dem nächsten unten in Chrome.
(n >> 31) | (!! n)
var s = (n>>31)|(!!n);
Verwendet die "Vorzeichenausbreitung nach rechts". Grundsätzlich werden durch Verschieben um 31 alle Bits außer dem Vorzeichen gelöscht. Wenn das Vorzeichen gesetzt wurde, ergibt dies -1, andernfalls ist es 0. Rechts
|
davon wird auf Positiv geprüft, indem der Wert in einen Booleschen Wert konvertiert wird (0 oder 1 [Übrigens: nicht numerische Zeichenfolgen, wie z!!'abc'
werden in diesem Fall 0, und nicht NaN]) verwendet dann eine bitweise ODER-Verknüpfung, um die Bits zu kombinieren.Dies scheint die beste durchschnittliche Leistung aller Browser zu sein (zumindest die beste in Chrome und Firefox), aber nicht die schnellste in ALLEN. Aus irgendeinem Grund ist der ternäre Operator im IE schneller.
n? n <0? -1: 1: 0
var s = n?n<0?-1:1:0;
Aus irgendeinem Grund am schnellsten im IE.
jsPerf
Durchgeführte Tests: https://jsperf.com/get-sign-from-value
quelle
Meine zwei Cent mit einer Funktion, die die gleichen Ergebnisse wie Math.sign liefert, dh Vorzeichen (-0) -> -0, Vorzeichen (-Infinity) -> -Infinity, Vorzeichen (null) -> 0 , Zeichen (undefiniert) -> NaN usw.
Jsperf lässt mich keinen Test oder keine Revision erstellen. Es tut mir leid, dass ich Ihnen keine Tests zur Verfügung stellen kann (ich habe jsbench.github.io ausprobiert, aber die Ergebnisse scheinen viel näher beieinander zu liegen als bei Jsperf ...).
Wenn jemand es bitte zu einer Jsperf-Revision hinzufügen könnte, wäre ich gespannt, wie es mit allen zuvor angegebenen Lösungen verglichen wird ...
Danke dir!
Jim.
EDIT :
Ich hätte schreiben sollen:
(
(+x && -1)
statt(x && -1)
) umsign('abc')
richtig zu handhaben (-> NaN)quelle
Math.sign wird in IE 11 nicht unterstützt. Ich kombiniere die beste Antwort mit der Antwort von Math.sign:
Jetzt kann man Math.sign direkt verwenden.
quelle