108 votes

Nombre.signe() en javascript

Je me demande s'il existe des méthodes non triviales pour trouver le signe d'un nombre ( fonction de signature ) ?
Il peut exister des solutions plus courtes, plus rapides et plus élégantes que la solution é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 vous pencher sur la comparaison des performances et des types de coercing. violon

Un long moment s'est écoulé. Plus loin, c'est surtout pour des raisons historiques.


Résultats

Pour l'instant, nous avons ces solutions :


1. Évidente et rapide

function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }

1.1. Modification de kbec - une coulée de type moins, plus performante, plus courte [plus rapide]

function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }

attention : sign("0") -> 1


2. Élégant, court, pas si rapide [plus lent]

function sign(x) { return x && x / Math.abs(x); }

attention : sign(+-Infinity) -> NaN , sign("0") -> NaN

A partir de Infinity est un numéro légal en JS, cette solution ne semble pas tout à fait correcte.


3. L'art... mais très lent [plus lent]

function sign(x) { return (x > 0) - (x < 0); }

4. Utilisation du décalage de bits
rapide, mais sign(-Infinity) -> 0

function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }

5. Type-safe [mégafast]

! Il semble que les navigateurs (en particulier la version 8 de Chrome) effectuent des optimisations magiques et cette solution s'avère être beaucoup plus performante que les autres, même que (1.1) bien qu'elle contienne 2 opérations supplémentaires et que logiquement elle ne puisse jamais être plus rapide.

function sign(x) {
    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}

Outils

  • jsperf des tests de préformance ;
  • violon - les tests de type-cast ;

Les améliorations sont les bienvenues !


[Hors sujet] Réponse acceptée

  • Andrey Tarantsov - +100 pour l'art, mais malheureusement, il est environ 5 fois plus lent que l'approche évidente.

  • Frédéric Hamidi - C'est en quelque sorte la réponse la plus votée (pour l'instant) et c'est plutôt cool, mais ce n'est pas du tout comme ça que les choses devraient être faites, à mon 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. Ce n'est pas si révolutionnaire, mais tout bien considéré, je considère cette approche comme la meilleure. Votez pour lui :)

0 votes

Je pense que votre réponse est plus rapide et plus courte que toutes les autres ici. Vous pouvez la rendre un peu plus rapide number > 0 ? 1 : number !== 0 ? -1 : 0 . Je présume que le test de l'égalité est plus rapide que celui de l'inégalité, bien que ce soit une affirmation importante et qu'elle dépende à la fois de l'implémentation et du matériel, et qu'elle doive être bien testée pour être vérifiée.

0 votes

Je ferais mieux d'utiliser == au lieu de === car il doit être un peu plus rapide dans ce cas.

0 votes

Quel est l'intérêt d'avoir 0 comme un cas particulier ?

82voto

kbec Points 1183

Version plus élégante de la solution rapide :

var sign = number?number<0?-1:1:0

7 votes

-1 pour avoir écrasé votre ternaire ensemble var sign = (number)? ((number < 0)? -1 : 1 ) : 0

3 votes

Math.sign(number)

29voto

Frédéric Hamidi Points 123646

En divisant le nombre par sa valeur absolue, on obtient également son signe. L'utilisation de l'opérateur logique AND, qui court-circuite, nous permet d'utiliser des cas particuliers. 0 pour qu'on ne finisse pas par la diviser :

var sign = number && number / Math.abs(number);

6 votes

Vous voudriez probablement var sign = number && number / Math.abs(number); dans l'affaire number = 0

0 votes

@NullUserException, vous avez tout à fait raison, 0 doit faire l'objet d'un boîtier spécial. Réponse mise à jour en conséquence. Merci :)

0 votes

Vous êtes le meilleur pour le moment. Mais j'espère qu'il y aura plus de réponses à l'avenir.

25voto

Andrey Tarantsov Points 4487

La fonction que vous recherchez s'appelle signum et la meilleure façon de la mettre en œuvre est la suivante :

function sgn(x) {
  return (x > 0) - (x < 0);
}

3 votes

Attendez. Il y a une erreur : for (x = -2 ; x <= 2 ; x++) console.log((x > 1) - (x < 1)) ; donne [-1, -1, -1, 0, 1] for (x = -2 ; x <= 2 ; x++) console.log((x > 0) - (x < 0)) ; donne [-1, -1, 0, 1, 1] correct.

16voto

Martijn Points 1

Ne devrait-il pas supporter les zéros signés de JavaScript (ECMAScript) ? Il semble fonctionner lorsqu'il renvoie x plutôt que 0 dans la fonction "megafast" :

function sign(x) {
    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN;
}

Cela le rend compatible avec un projet de Math.sign de l'ECMAScript ( MDN ) :

Renvoie le signe de x, indiquant si x est positif, négatif ou nul.

  • Si x est NaN, le résultat est NaN.
  • Si x est égal à 0, le résultat est égal à 0.
  • Si x est +0, le résultat est +0.
  • Si x est négatif et non 0, le résultat est 1.
  • Si x est positif et non +0, le résultat est +1.

0 votes

Mécanisme incroyablement rapide et intéressant, je suis impressionné. J'attends d'autres tests.

4voto

Toxiro Points 15
var sign = number >> 31 | -number >>> 31;

Super rapide si vous n'avez pas besoin de l'infini et que vous savez que le nombre est un entier, trouvé dans la source openjdk-7 : java.lang.Integer.signum()

1 votes

Cela échoue pour les petites fractions négatives comme -0,5. (Il semble que la source provienne d'une implémentation spécifique pour Integers).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X