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
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 ?3 votes
Le fait est que parfois
0
est un cas particulier0 votes
Il y a une différence entre ma solution et la vôtre. Il n'est pas nécessaire de vérifier que le nombre est supérieur à zéro car 0==vrai, donc si le nombre est égal à faux et n'est pas inférieur à 0, il est supérieur. Une vérification en moins peut donner plus d'efficacité, en plus d'être tapé à la manière des perfectionnistes.
0 votes
Je comprends ce que vous voulez dire. Le mot clé ici est "évident". Je veux donc que ce soit vraiment évident. J'espère que vous êtes d'accord que votre solution est un peu moins évidente. En outre, elle comporte le même nombre de vérifications - 2, mais elle est vraiment plus performante en raison de la suppression d'un cast de type (
x > 0 ?
- casted to number,x ?
- pas). Donc si cela ne vous dérange pas, je vais mettre votre solution comme une "modification" de la première.1 votes
J'ai réalisé un ensemble de tests JSPerf (avec différents types d'entrées) pour tester chaque algorithme, que vous pouvez trouver ici : jsperf.com/signatures Les résultats peuvent ne pas être ceux indiqués dans ce post !
0 votes
@jmendeth, j'ai exécuté votre jsperf et "safe" était 3 fois plus rapide que "sign1b", ce qui n'a aucun sens. je n'ai jamais aimé jsperf :)
2 votes
@disfated, lequel des deux ? Bien sûr, si vous exécutez le
test everything
version, Safe refusera de tester les valeurs spéciales, donc ce sera plus rapide ! Essayez d'exécuter leonly integers
à la place. De plus, JSPerf ne fait que son travail, ce n'est pas une question d'appréciation :)1 votes
C'est une belle question
1 votes
Whoa, mon approche est lente ! Merci pour le test ; je ne l'aurais jamais deviné. Curieusement, (x>0)-(x<0) est la façon dont nous avons procédé au début des années 2000 dans ACM ICPC parce que c'était la solution la plus rapide du marché (l'assembleur en ligne étant interdit par les règles) et aussi une qui est évidemment correcte.
2 votes
Selon les tests de jsperf, il s'avère que
typeof x === "number"
met un peu de magie sur les performances. S'il vous plaît, faites plus d'essais, surtout FF, Opera et IE pour que ce soit clair.4 votes
Pour être complet, j'ai ajouté un nouveau test jsperf.com/signs/7 para
Math.sign()
(0===0, pas aussi rapide que "Safe") qui est apparu dans FF25 et est à venir dans chrome.0 votes
@AndreyTarantsov : C'est peut-être parce que dans JS la
<
y>
renvoient des objets de type booléen (contrairement au C, qui renvoie un int 0 ou 1 je pense), donc deux conversions de type doivent être effectuées afin de faire la soustraction.0 votes
La réponse acceptée (n°5) prend-elle en compte les fractions ? Il semble que les réponses avec "Undefined" lorsque x<0.5 ?
0 votes
@Ideogram, c'est le cas. Pourriez-vous fournir des données exactes
x
ce qui, comme vous le supposez, conduit à des résultats erronés ?0 votes
6. L'autochtone :
Math.sign
0 votes
Les performances sont probablement dues au fait que vous éliminez des objets (
new Number()
) afin que le reste du code n'ait à gérer que les littéraux. En fonction de votre scénario, vous pourriez abandonner le support des objets, mais je ne le ferais pas.