Lecture de la spécification ECMAScript 5.1 , +0
et -0
sont distingués.
Pourquoi alors +0 === -0
évalue- true
t-il?
Object.is
pour distinguer +0 et -0
Lecture de la spécification ECMAScript 5.1 , +0
et -0
sont distingués.
Pourquoi alors +0 === -0
évalue- true
t-il?
Object.is
pour distinguer +0 et -0
Réponses:
JavaScript utilise la norme IEEE 754 pour représenter les nombres. De Wikipedia :
Le zéro signé est zéro avec un signe associé. En arithmétique ordinaire, −0 = +0 = 0. Cependant, en calcul, certaines représentations numériques permettent l'existence de deux zéros, souvent désignés par −0 (zéro négatif) et +0 (zéro positif) . Cela se produit dans certaines représentations de nombres signés pour les entiers et dans la plupart des représentations de nombres à virgule flottante. Le nombre 0 est généralement codé comme +0, mais peut être représenté par +0 ou −0.
La norme IEEE 754 pour l'arithmétique en virgule flottante (actuellement utilisée par la plupart des ordinateurs et langages de programmation qui prennent en charge les nombres à virgule flottante) nécessite à la fois +0 et −0. Les zéros peuvent être considérés comme une variante de la droite étendue des nombres réels telle que 1 / −0 = −∞ et 1 / + 0 = + ∞, la division par zéro n'est définie que pour ± 0 / ± 0 et ± ∞ / ± ∞ .
L'article contient de plus amples informations sur les différentes représentations.
C'est donc la raison pour laquelle, techniquement, les deux zéros doivent être distingués.
Cependant,
+0 === -0
évalue à vrai. Pourquoi donc (...) ?
Ce comportement est explicitement défini dans la section 11.9.6 , l' algorithme de comparaison d'égalité stricte (c'est moi qui souligne en partie):
La comparaison
x === y
, oùx
ety
sont des valeurs, produit vrai ou faux . Une telle comparaison est effectuée comme suit:(...)
Si Type (x) est Nombre, alors
- Si x est NaN, renvoie false.
- Si y est NaN, renvoie false.
- Si x est la même valeur numérique que y, renvoie true.
- Si x est +0 et y est −0, renvoie vrai.
- Si x est −0 et y est +0, renvoie vrai.
- Renvoie false.
(...)
(La même chose vaut pour +0 == -0
btw.)
Il semble logiquement traiter +0
et -0
comme égal. Sinon, nous devrions en tenir compte dans notre code et moi, personnellement, je ne veux pas faire cela;)
Remarque:
ES2015 introduit une nouvelle méthode de comparaison, Object.is
. Object.is
fait une distinction explicite entre -0
et +0
:
Object.is(-0, +0); // false
1/0 === Infinity; // true
et 1/-0 === -Infinity; // true
.
1 === 1
et +0 === -0
mais 1/+0 !== 1/-0
. Comme c'est bizarre!
+0 !== -0
;) Cela pourrait vraiment créer des problèmes.
0 !== +0
/ 0 !== -0
, ce qui créerait en effet aussi des problèmes!
J'ajouterai ceci comme réponse car j'ai oublié le commentaire de @ user113716.
Vous pouvez tester -0 en faisant ceci:
function isMinusZero(value) {
return 1/value === -Infinity;
}
isMinusZero(0); // false
isMinusZero(-0); // true
e±308
, votre nombre ne peut être représenté que sous forme dénormalisée et différentes implémentations ont des opinions différentes sur où les soutenir ou non. Le fait est que sur certaines machines dans certains modes à virgule flottante, votre nombre est représenté comme -0
et sur d'autres comme un nombre dénormalisé 0.000000000000001e-308
. Such floats, so fun
Je viens de tomber sur un exemple où +0 et -0 se comportent en effet très différemment:
Math.atan2(0, 0); //returns 0
Math.atan2(0, -0); //returns Pi
Attention: même en utilisant Math.round sur un nombre négatif comme -0,0001, il sera en fait -0 et peut bousiller certains calculs ultérieurs comme indiqué ci-dessus.
Un moyen rapide et sale de résoudre ce problème est de faire comme:
if (x==0) x=0;
ou juste:
x+=0;
Cela convertit le nombre en +0 au cas où il serait de -0.
dans le norme IEEE 754 utilisée pour représenter le type Number en JavaScript, le signe est représenté par un bit (un 1 indique un nombre négatif).
En conséquence, il existe à la fois une valeur négative et une valeur positive pour chaque nombre représentable, y compris 0
.
C'est pourquoi les deux -0
et +0
existent.
Répondre au titre original Are +0 and -0 the same?
:
brainslugs83
(dans les commentaires de la réponse de Spudley
) a souligné un cas important dans lequel +0 et -0 dans JS ne sont pas les mêmes - implémentés en fonction:
var sign = function(x) {
return 1 / x === 1 / Math.abs(x);
}
Ceci, autre que le standard, Math.sign
renverra le signe correct de +0 et -0.
Il existe deux valeurs possibles (représentations binaires) pour 0. Ce n'est pas unique. Cela peut se produire en particulier dans les nombres à virgule flottante. C'est parce que les nombres à virgule flottante sont en fait stockés sous forme de formule.
Les entiers peuvent également être stockés de manière distincte. Vous pouvez avoir une valeur numérique avec un bit de signe supplémentaire, donc dans un espace de 16 bits, vous pouvez stocker une valeur entière de 15 bits et un bit de signe. Dans cette représentation, les valeurs 1000 (hexadécimal) et 0000 valent toutes deux 0, mais l'une d'elles est +0 et l'autre est -0.
Cela pourrait être évité en soustrayant 1 de la valeur entière afin qu'elle varie de -1 à -2 ^ 16, mais ce serait peu pratique.
Une approche plus courante consiste à stocker les entiers dans «deux compléments», mais apparemment, ECMAscript a choisi de ne pas le faire. Dans cette méthode, les nombres vont de 0000 à 7FFF positifs. Les nombres négatifs commencent de FFFF (-1) à 8000.
Bien sûr, les mêmes règles s'appliquent également aux nombres entiers plus grands, mais je ne veux pas que mon F s'use. ;)
+0 === -0
un peu bizarre. Parce que maintenant nous avons 1 === 1
et +0 === -0
mais 1/+0 !== 1/-0
...
+0 === -0
bien que les représentations à deux bits soient différentes.
Je le blâmerais sur la méthode Strict Equality Comparison ('==='). Regardez la section 4d
voir 7.2.13 Comparaison d'égalité stricte sur la spécification
Wikipedia a un bon article pour expliquer ce phénomène: http://en.wikipedia.org/wiki/Signed_zero
En bref, +0 et -0 sont définis dans les spécifications de virgule flottante IEEE. Les deux sont techniquement distincts de 0 sans signe, qui est un entier, mais en pratique ils sont tous évalués à zéro, de sorte que la distinction peut être ignorée à toutes fins pratiques.