A leitura através da especificação ECMAScript 5,1 , +0
e -0
são distinguidos.
Por que, então, +0 === -0
avalia a true
?
Object.is
para distinguir +0 e -0
A leitura através da especificação ECMAScript 5,1 , +0
e -0
são distinguidos.
Por que, então, +0 === -0
avalia a true
?
Object.is
para distinguir +0 e -0
Respostas:
JavaScript usa o padrão IEEE 754 para representar números. Da Wikipedia :
Zero assinado é zero com um sinal associado. Na aritmética comum, −0 = +0 = 0. No entanto, na computação, algumas representações numéricas permitem a existência de dois zeros, geralmente denotados por −0 (zero negativo) e +0 (zero positivo) . Isso ocorre em algumas representações numéricas assinadas para números inteiros e na maioria das representações numéricas de ponto flutuante. O número 0 geralmente é codificado como +0, mas pode ser representado por +0 ou −0.
O padrão IEEE 754 para aritmética de ponto flutuante (atualmente usado pela maioria dos computadores e linguagens de programação que suportam números de ponto flutuante) requer +0 e -0. Os zeros podem ser considerados uma variante da linha de número real estendida, de modo que 1 / −0 = −∞ e 1 / + 0 = + ∞, a divisão por zero é indefinida apenas para ± 0 / ± 0 e ± ∞ / ± ∞ .
O artigo contém mais informações sobre as diferentes representações.
Portanto, essa é a razão pela qual, tecnicamente, os dois zeros devem ser distinguidos.
No entanto,
+0 === -0
avalia como verdadeiro. Por que é que (...) ?
Esse comportamento é definido explicitamente na seção 11.9.6 , o Algoritmo de comparação estrita de igualdade (ênfase parcialmente minha):
A comparação
x === y
, ondex
ey
são valores, produz verdadeiro ou falso . Essa comparação é realizada da seguinte maneira:(...)
Se o Tipo (x) for Número, então
- Se x for NaN, retorne false.
- Se y for NaN, retorne false.
- Se x é o mesmo valor numérico que y, retorne true.
- Se x é +0 e y é −0, retorne true.
- Se x é −0 e y é +0, retorne true.
- Retorna falso.
(...)
(O mesmo vale para +0 == -0
btw.)
Parece logicamente tratar +0
e -0
igual. Caso contrário, teríamos que levar isso em conta em nosso código e eu, pessoalmente, não quero fazer isso;)
Nota:
O ES2015 apresenta um novo método de comparação Object.is
,. Object.is
distingue explicitamente entre -0
e +0
:
Object.is(-0, +0); // false
1/0 === Infinity; // true
e 1/-0 === -Infinity; // true
.
1 === 1
e +0 === -0
mas 1/+0 !== 1/-0
. Que estranho!
+0 !== -0
;) Isso pode realmente criar problemas.
0 !== +0
/ 0 !== -0
, o que também criaria problemas também!
Acrescentarei isso como resposta, porque ignorei o comentário de @ user113716.
Você pode testar -0 fazendo o seguinte:
function isMinusZero(value) {
return 1/value === -Infinity;
}
isMinusZero(0); // false
isMinusZero(-0); // true
e±308
seu número pode ser representado apenas na forma desnormalizada e diferentes implementações têm opiniões diferentes sobre onde apoiá-los ou não. O ponto é que, em algumas máquinas, em alguns modos de ponto flutuante, seu número é representado como -0
em outras, como número desnormalizado 0.000000000000001e-308
. Esses carros alegóricos, tão divertido
Acabei de encontrar um exemplo em que +0 e -0 se comportam de maneira muito diferente:
Math.atan2(0, 0); //returns 0
Math.atan2(0, -0); //returns Pi
Cuidado: mesmo ao usar Math.round em um número negativo como -0.0001, ele será realmente -0 e poderá estragar alguns cálculos subsequentes, como mostrado acima.
A maneira rápida e suja de corrigir isso é fazer algo como:
if (x==0) x=0;
ou apenas:
x+=0;
Isso converte o número em +0, caso seja -0.
No padrão IEEE 754 usado para representar o tipo Number em JavaScript, o sinal é representado por um bit (1 indica um número negativo).
Como resultado, existe um valor negativo e um positivo para cada número representável, inclusive 0
.
É por isso que ambos -0
e +0
existem.
Respondendo ao título original Are +0 and -0 the same?
:
brainslugs83
(nos comentários da resposta de Spudley
) apontou um caso importante em que +0 e -0 em JS não são os mesmos - implementados como função:
var sign = function(x) {
return 1 / x === 1 / Math.abs(x);
}
Isso, além do padrão, Math.sign
retornará o sinal correto de +0 e -0.
Existem dois valores possíveis (representações de bits) para 0. Isso não é exclusivo. Especialmente em números de ponto flutuante, isso pode ocorrer. Isso ocorre porque os números de ponto flutuante são realmente armazenados como um tipo de fórmula.
Os números inteiros também podem ser armazenados de maneiras separadas. Você pode ter um valor numérico com um bit de sinal adicional; portanto, em um espaço de 16 bits, você pode armazenar um valor inteiro de 15 bits e um bit de sinal. Nesta representação, o valor 1000 (hex) e 0000 são 0, mas um deles é +0 e o outro é -0.
Isso poderia ser evitado subtraindo 1 do valor inteiro, variando de -1 a -2 ^ 16, mas isso seria inconveniente.
Uma abordagem mais comum é armazenar números inteiros em 'dois complementos', mas aparentemente o ECMAscript optou por não. Neste método, os números variam de 0000 a 7FFF positivo. Os números negativos começam em FFFF (-1) a 8000.
Obviamente, as mesmas regras também se aplicam a números inteiros maiores, mas não quero que meu F se esgote. ;)
+0 === -0
um pouco estranho. Porque agora nós temos 1 === 1
e +0 === -0
mas 1/+0 !== 1/-0
...
+0 === -0
apesar das representações de dois bits serem diferentes.
Eu culparia o método de comparação estrita da igualdade ('==='). Veja a seção 4d
consulte 7.2.13 Comparação estrita de igualdade na especificação
A Wikipedia tem um bom artigo para explicar esse fenômeno: http://en.wikipedia.org/wiki/Signed_zero
Em resumo, ambos +0 e -0 são definidos nas especificações de ponto flutuante IEEE. Ambos são tecnicamente distintos de 0 sem um sinal, que é um número inteiro, mas, na prática, todos são avaliados como zero, de modo que a distinção pode ser ignorada para todos os fins práticos.