Ciekawe, czy są jakieś nietrywialne sposoby znalezienia znaku liczby ( funkcja signum )?
Mogą być krótsze / szybsze / bardziej eleganckie rozwiązania niż oczywiste
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
Krótka odpowiedź!
Użyj tego, a będziesz bezpieczny i szybki (źródło: moz )
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
Możesz przyjrzeć się skrzypcom porównawczym wydajności i wymuszania typu
Minęło dużo czasu. Dalej jest głównie ze względów historycznych.
Wyniki
Na razie mamy takie rozwiązania:
1. Oczywiste i szybkie
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. Modyfikacja z kbec - jeden typ rzadziej rzucany, wydajniejszy , krótszy [najszybszy]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
Uwaga: sign("0") -> 1
2. Eleganckie, krótkie, nie tak szybkie [najwolniejsze]
function sign(x) { return x && x / Math.abs(x); }
Ostrzeżenie: sign(+-Infinity) -> NaN
,sign("0") -> NaN
Jak Infinity
na numer prawny w JS, to rozwiązanie nie wydaje się w pełni poprawne.
3. Sztuka ... ale bardzo wolno [najwolniej]
function sign(x) { return (x > 0) - (x < 0); }
4. Używając szybkiego przesunięcia bitowego
, alesign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Bezpieczne dla typów [megafast]
! Wygląda na to, że przeglądarki (zwłaszcza Chrome v8) dokonują magicznych optymalizacji i to rozwiązanie okazuje się znacznie wydajniejsze niż inne, nawet niż (1.1), mimo że zawiera 2 dodatkowe operacje i logicznie rzecz biorąc, nigdy nie może być szybsze.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
Przybory
- testy wydajności jsperf ;
- skrzypce - testy typu cast;
Ulepszenia są mile widziane!
[Offtopic] Zaakceptowana odpowiedź
Andrey Tarantsov - +100 za sztukę, ale niestety jest to około 5 razy wolniejsze niż oczywiste podejście
Frédéric Hamidi - jakoś najbardziej chwalona odpowiedź (jak na razie piszę) i jest całkiem fajna, ale zdecydowanie nie tak należy to robić, imho. Ponadto nie obsługuje poprawnie liczb nieskończoności, które są również liczbami, wiesz.
kbec - to ulepszenie oczywistego rozwiązania. Nie tak rewolucyjne, ale biorąc wszystko razem uważam to podejście za najlepsze. Zagłosuj na niego :)
źródło
0
jest to szczególny przypadektest everything
wersję, Safe odmówi przetestowania specjalnych wartości, więc będzie szybszy!only integers
Zamiast tego spróbuj uruchomić test. Poza tym JSPerf po prostu wykonuje swoją pracę, nie chodzi o to, żeby go lubić. :)typeof x === "number"
magia. Proszę, zrób więcej przebiegów, zwłaszcza FF, Opera i IE, aby było jasne.Math.sign()
(0 === 0, nie tak szybki jak "Safe"), który pojawił się w FF25 i nadchodzi w chrome.Odpowiedzi:
Bardziej elegancka wersja szybkiego rozwiązania:
źródło
var sign = (number)? ((number < 0)? -1 : 1 ) : 0
Math.sign(number)
Dzielenie liczby przez jej wartość bezwzględną również daje jej znak. Korzystanie ze zwierającego operatora logicznego AND pozwala nam na specjalne wielkości,
0
więc nie kończymy na dzieleniu przez to:źródło
var sign = number && number / Math.abs(number);
na wszelki wypadeknumber = 0
0
musi mieć specjalną wielkość liter . Odpowiednio zaktualizowano odpowiedź. Dzięki :)Funkcja, której szukasz, nazywa się signum , a najlepszym sposobem jej wdrożenia jest:
źródło
Czy to nie powinno obsługiwać zer podpisanych w JavaScript (ECMAScript)? Wydaje się, że działa przy zwracaniu x zamiast 0 w funkcji „megafast”:
To sprawia, że jest kompatybilny z wersją roboczą Math.sign ( MDN ) ECMAScript :
źródło
Dla osób, które są zainteresowane tym, co się dzieje z najnowszymi przeglądarkami, w wersji ES6 dostępna jest natywna metoda Math.sign . Wsparcie możesz sprawdzić tutaj .
W zasadzie to wraca
-1
,1
,0
lubNaN
źródło
Superszybki, jeśli nie potrzebujesz Infinity i wiesz, że liczba jest liczbą całkowitą, znalezioną w źródle openjdk-7:
java.lang.Integer.signum()
źródło
Pomyślałem, że dodam to dla zabawy:
0 i NaN zwróci -1
działa dobrze na +/- Nieskończoność
źródło
Rozwiązanie, które działa na wszystkich liczbach, a także
0
i-0
, a takżeInfinity
i-Infinity
, to:Zobacz pytanie „ Czy +0 i -0 to to samo? ”, Aby uzyskać więcej informacji.
Ostrzeżenie: Żadna z tych odpowiedzi, w tym obecnie standardowym
Math.sign
praca będzie na razie0
vs-0
. Może to nie stanowić problemu dla Ciebie, ale w niektórych implementacjach fizyki może to mieć znaczenie.źródło
Możesz przesunąć nieco liczbę i sprawdzić najbardziej znaczący bit (MSB). Jeśli MSB jest 1, to liczba jest ujemna. Jeśli jest 0, to liczba jest dodatnia (lub 0).
źródło
var sign = number < 0 : 1 : 0
n & 0x80000000
maskę bitową. Co do konwersji na 0,1, -1:n && (n & 0x80000000 ? -1 : 1)
-5e32
i się zepsuł.ToInt32
. Jeśli tam przeczytasz (rozdział 9.5), istnieje moduł, który wpływa na wartość liczb, ponieważ zakres 32-bitowej liczby całkowitej jest mniejszy niż zakres typu js Number. Więc to nie zadziała dla tych wartości lub nieskończoności. Jednak nadal podoba mi się odpowiedź.Właśnie miałem zadać to samo pytanie, ale znalazłem rozwiązanie, zanim skończyłem pisać, zobaczyłem, że to pytanie już istnieje, ale nie widziałem tego rozwiązania.
(n >> 31) + (n > 0)
wydaje się być szybszy po dodaniu trójskładnika
(n >> 31) + (n>0?1:0)
źródło
Bardzo podobne do odpowiedzi Martijna
Uważam to za bardziej czytelne. Ponadto (lub, w zależności od twojego punktu widzenia, jednakże), określa również rzeczy, które można zinterpretować jako liczbę; np. wraca
-1
po wyświetleniu'-5'
.źródło
Nie widzę praktycznego sensu zwracania -0 i 0 z,
Math.sign
więc moja wersja to:źródło
Metody, które znam, są następujące:
Math.sign (n)
var s = Math.sign(n)
Jest to funkcja natywna, ale jest najwolniejsza ze wszystkich ze względu na narzut wywołania funkcji. Obsługuje jednak „NaN”, gdzie pozostałe poniżej mogą po prostu przyjąć 0 (tj. Math.sign („abc”) to NaN).
((n> 0) - (n <0))
var s = ((n>0) - (n<0));
W tym przypadku tylko lewa lub prawa strona może być 1 na podstawie znaku. Powoduje to
1-0
(1),0-1
(-1) lub0-0
(0).Szybkość tego wydaje się łeb w łeb z następną poniżej w Chrome.
(n >> 31) | (!! n)
var s = (n>>31)|(!!n);
Używa "przesunięcia w prawo propagującego znak". Zasadniczo przesunięcie o 31 zrzuca wszystkie bity z wyjątkiem znaku. Jeśli znak został ustawiony, daje to -1, w przeciwnym razie 0. Po prawej stronie
|
testuje wartość dodatnią, konwertując wartość na wartość logiczną (0 lub 1 [BTW: łańcuchy nienumeryczne, np.!!'abc'
, stają się w tym przypadku 0 i not NaN]) następnie używa bitowej operacji OR do łączenia bitów.Wydaje się, że jest to najlepsza średnia wydajność we wszystkich przeglądarkach (najlepsza przynajmniej w Chrome i Firefox), ale nie najszybsza we WSZYSTKICH z nich. Z jakiegoś powodu operator trójskładnikowy jest szybszy w IE.
n? n <0 a -1: 1: 0
var s = n?n<0?-1:1:0;
Z jakiegoś powodu najszybsza w IE.
jsPerf
Wykonane testy: https://jsperf.com/get-sign-from-value
źródło
Moje dwa centy, z funkcją, która zwraca te same wyniki co Math.sign, tj. Sign (-0) -> -0, sign (-Infinity) -> -Infinity, sign (null) -> 0 , znak (nieokreślony) -> NaN itp.
Jsperf nie pozwala mi stworzyć testu ani wersji, przepraszam, że nie mogę dostarczyć Ci testów (wypróbowałem jsbench.github.io, ale wyniki wydają się być znacznie bliżej siebie niż w przypadku Jsperf ...)
Gdyby ktoś mógł dodać to do wersji Jsperf, byłbym ciekawy, jak wypada na tle wszystkich podanych wcześniej rozwiązań ...
Dziękuję Ci!
Jim.
EDYCJA :
Powinienem był napisać:
(
(+x && -1)
zamiast(x && -1)
) w celusign('abc')
poprawnej obsługi (-> NaN)źródło
Math.sign nie jest obsługiwany w IE 11. Łączę najlepszą odpowiedź z odpowiedzią Math.sign:
Teraz można bezpośrednio korzystać z Math.sign.
źródło