Je me demande s'il existe des moyens non triviaux de trouver le signe des nombres ( fonction signum )?
Peut être des solutions plus courtes / plus rapides / plus élégantes que l'évidente
var sign = number > 0 ? 1 : number < 0 ? -1 : 0;
Réponse courte!
Utilisez ceci et vous serez sûr et rapide (source: moz )
if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };
Vous voudrez peut-être examiner les performances et le violon de comparaison contraignant sur le type
Le temps a passé. De plus, c'est principalement pour des raisons historiques.
Résultats
Pour l'instant, nous avons ces solutions:
1. Évident et rapide
function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }
1.1. Modification de kbec - un type cast moins, plus performant, plus court [plus rapide]
function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }
mise en garde: sign("0") -> 1
2. Élégant, court, pas si rapide [le plus lent]
function sign(x) { return x && x / Math.abs(x); }
Mise en garde: sign(+-Infinity) -> NaN
,sign("0") -> NaN
À partir d' Infinity
un numéro légal dans JS, cette solution ne semble pas tout à fait correcte.
3. L'art ... mais très lent [le plus lent]
function sign(x) { return (x > 0) - (x < 0); }
4. Utilisation rapide du bit-shift
, maissign(-Infinity) -> 0
function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }
5. Type-safe [megafast]
! On dirait que les navigateurs (en particulier le v8 de chrome) font des optimisations magiques et cette solution s'avère beaucoup plus performante que d'autres, même que (1.1) malgré qu'elle contienne 2 opérations supplémentaires et ne peut logiquement jamais être plus rapide.
function sign(x) {
return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}
Outils
Les améliorations sont les bienvenues!
[Offtopic] Réponse acceptée
Andrey Tarantsov - +100 pour l'art, mais malheureusement, c'est environ 5 fois plus lent que l'approche évidente
Frédéric Hamidi - en quelque sorte la réponse la plus votée (pour le moment) et c'est plutôt cool, mais ce n'est certainement pas la façon dont les choses devraient être faites, à mon humble avis. De plus, il ne gère pas correctement les nombres Infinity, qui sont aussi des nombres, vous savez.
kbec - est une amélioration de la solution évidente. Pas si révolutionnaire, mais dans l'ensemble, je considère que cette approche est la meilleure. Votez pour lui :)
la source
0
est un cas particuliertest everything
version, Safe refusera de tester les valeurs spéciales, donc ce sera plus rapide! Essayezonly integers
plutôt d' exécuter le test. De plus, JSPerf fait juste son travail, il ne s'agit pas de l'aimer. :)typeof x === "number"
met un peu de magie sur performace. S'il vous plaît, faites plus de courses, en particulier FF, Opera et IE pour que ce soit clair.Math.sign()
(0 === 0, pas aussi rapide que "Safe") qui est apparu dans FF25 et est à venir dans Chrome.Réponses:
Version plus élégante de la solution rapide:
la source
var sign = (number)? ((number < 0)? -1 : 1 ) : 0
Math.sign(number)
Diviser le nombre par sa valeur absolue donne également son signe. L'utilisation de l'opérateur logique AND de court-circuit nous permet de faire un cas particulier
0
afin de ne pas finir par diviser par lui:la source
var sign = number && number / Math.abs(number);
au cas oùnumber = 0
0
doit être avec une casse spéciale. Réponse mise à jour en conséquence. Merci :)La fonction que vous recherchez s'appelle signum , et la meilleure façon de l'implémenter est:
la source
Cela ne devrait-il pas prendre en charge les zéros signés de JavaScript (ECMAScript)? Cela semble fonctionner en renvoyant x plutôt que 0 dans la fonction «megafast»:
Cela le rend compatible avec un brouillon de Math.sign ( MDN ) d' ECMAScript :
la source
Pour les personnes intéressées par ce qui se passe avec les derniers navigateurs, dans la version ES6, il existe une méthode native Math.sign . Vous pouvez consulter le support ici .
Fondamentalement , il retourne
-1
,1
,0
ouNaN
la source
Superfast si vous n'avez pas besoin d'Infinity et savez que le nombre est un entier, trouvé dans openjdk-7 source:
java.lang.Integer.signum()
la source
J'ai pensé ajouter ceci juste pour le plaisir:
0 et NaN renverra -1
fonctionne bien sur +/- Infinity
la source
Une solution qui fonctionne sur tous les nombres, ainsi que sur
0
et-0
, ainsi que surInfinity
et-Infinity
, est:Voir la question « Est-ce que +0 et -0 sont identiques? » Pour plus d'informations.
Avertissement: Aucune de ces réponses, y compris le maintenant standard
Math.sign
travaillera sur le cas0
vs-0
. Ce n'est peut-être pas un problème pour vous, mais dans certaines implémentations physiques, cela peut avoir de l'importance.la source
Vous pouvez décaler le nombre de bits et vérifier le bit le plus significatif (MSB). Si le MSB est un 1, le nombre est négatif. S'il vaut 0, le nombre est positif (ou 0).
la source
var sign = number < 0 : 1 : 0
n & 0x80000000
comme un bitmask. Quant à la conversion en 0,1, -1:n && (n & 0x80000000 ? -1 : 1)
-5e32
et il s'est cassé.ToInt32
. Si vous y lisez (section 9.5), il existe un module qui affecte la valeur des nombres puisque la plage d'un entier 32 bits est inférieure à la plage du type js Number. Cela ne fonctionnera donc pas pour ces valeurs ou les infinis. J'aime toujours la réponse.J'étais sur le point de poser la même question, mais je suis venu à une solution avant d'avoir fini d'écrire, j'ai vu que cette question existait déjà, mais je n'ai pas vu cette solution.
(n >> 31) + (n > 0)
cela semble être plus rapide en ajoutant un ternaire cependant
(n >> 31) + (n>0?1:0)
la source
Très similaire à la réponse de Martijn est
Je le trouve plus lisible. Aussi (ou, selon votre point de vue, cependant), il groks aussi des choses qui peuvent être interprétées comme un nombre; par exemple, il revient
-1
lorsqu'il est présenté avec'-5'
.la source
Je ne vois aucun sens pratique de retour de -0 et 0 à partir de
Math.sign
donc ma version est:la source
Les méthodes que je connais sont les suivantes:
Math.sign (n)
var s = Math.sign(n)
C'est la fonction native, mais elle est la plus lente de toutes en raison de la surcharge d'un appel de fonction. Il gère cependant 'NaN' où les autres ci-dessous peuvent simplement supposer 0 (c'est-à-dire que Math.sign ('abc') est NaN).
((n> 0) - (n <0))
var s = ((n>0) - (n<0));
Dans ce cas, seul le côté gauche ou droit peut être un 1 basé sur le signe. Cela se traduit par
1-0
(1),0-1
(-1) ou0-0
(0).La vitesse de celui-ci semble au coude à coude avec le suivant ci-dessous dans Chrome.
(n >> 31) | (!! n)
var s = (n>>31)|(!!n);
Utilise le "décalage vers la droite de propagation de signe". Fondamentalement, le décalage de 31 supprime tous les bits sauf le signe. Si le signe a été défini, cela donne -1, sinon il vaut 0. À droite,
|
il teste le positif en convertissant la valeur en booléen (0 ou 1 [BTW: chaînes non numériques, comme!!'abc'
, deviennent 0 dans ce cas, et not NaN]) utilise alors une opération OR au niveau du bit pour combiner les bits.Cela semble être la meilleure performance moyenne sur tous les navigateurs (au moins dans Chrome et Firefox), mais pas la plus rapide dans TOUS. Pour une raison quelconque, l'opérateur ternaire est plus rapide dans IE.
n? n <0? -1: 1: 0
var s = n?n<0?-1:1:0;
Le plus rapide dans IE pour une raison quelconque.
jsPerf
Tests effectués: https://jsperf.com/get-sign-from-value
la source
Mes deux cents, avec une fonction qui renvoie les mêmes résultats que Math.sign ferait, c'est-à-dire signe (-0) -> -0, signe (-Infinity) -> -Infinity, signe (null) -> 0 , signe (non défini) -> NaN, etc.
Jsperf ne me laisse pas créer de test ou de révision, désolé de ne pas pouvoir vous fournir de tests (j'ai essayé jsbench.github.io, mais les résultats semblent beaucoup plus proches les uns des autres qu'avec Jsperf ...)
Si quelqu'un pouvait s'il vous plaît l'ajouter à une révision Jsperf, je serais curieux de voir comment cela se compare à toutes les solutions précédemment données ...
Je vous remercie!
Jim.
MODIFIER :
J'aurais dû écrire:
(
(+x && -1)
au lieu de(x && -1)
) pour gérersign('abc')
correctement (-> NaN)la source
Math.sign n'est pas pris en charge sur IE 11. Je combine la meilleure réponse avec la réponse Math.sign:
Maintenant, on peut utiliser directement Math.sign.
la source