¿Son +0 y -0 iguales?


172

Lectura a través de la especificación ECMAScript 5.1 , +0y -0se distinguen.

¿Por qué entonces +0 === -0evalúa a true?


posible duplicado de diferenciar +0 y -0
GolezTrol

66
Tenga en cuenta que en ES2015 puede usar Object.ispara distinguir +0 y -0
Benjamin Gruenbaum

Citando a David Flanagan de JS, la guía definitiva : el subflujo ocurre cuando el resultado de una operación numérica está más cerca de cero que el número representable más pequeño. En este caso, JavaScript devuelve 0. Si se produce un desbordamiento de un número negativo, JavaScript devuelve un valor especial conocido como "cero negativo".
RBT

Respuestas:


194

JavaScript utiliza el estándar IEEE 754 para representar números. De Wikipedia :

El cero con signo es cero con un signo asociado. En aritmética ordinaria, −0 = +0 = 0. Sin embargo, en informática, algunas representaciones numéricas permiten la existencia de dos ceros, a menudo denotados por −0 (cero negativo) y +0 (cero positivo) . Esto ocurre en algunas representaciones de números con signo para enteros, y en la mayoría de las representaciones de números de coma flotante. El número 0 generalmente se codifica como +0, pero se puede representar con +0 o −0.

El estándar IEEE 754 para aritmética de coma flotante (utilizado actualmente por la mayoría de las computadoras y lenguajes de programación que admiten números de coma flotante) requiere tanto +0 como −0. Los ceros se pueden considerar como una variante de la recta numérica real extendida de modo que 1 / −0 = −∞ y 1 / + 0 = + ∞, la división por cero solo está indefinida para ± 0 / ± 0 y ± ∞ / ± ∞ .

El artículo contiene más información sobre las diferentes representaciones.

Entonces esta es la razón por la cual, técnicamente, ambos ceros tienen que distinguirse.

Sin embargo, se +0 === -0evalúa como verdadero. Porqué es eso (...) ?

Este comportamiento se define explícitamente en la sección 11.9.6 , Algoritmo estricto de comparación de igualdad (el énfasis es parcialmente mío):

La comparación x === y, donde xy yson valores, produce verdadero o falso . Dicha comparación se realiza de la siguiente manera:

(...)

  • Si Tipo (x) es Número, entonces

    1. Si x es NaN, devuelve falso.
    2. Si y es NaN, devuelve falso.
    3. Si x es el mismo valor numérico que y, devuelve verdadero.
    4. Si x es +0 e y es −0, devuelve verdadero.
    5. Si x es −0 e y es +0, devuelve verdadero.
    6. Falso retorno.

(...)

(Lo mismo vale para +0 == -0BTW).

Parece lógicamente tratar +0e -0igual. De lo contrario, tendríamos que tener esto en cuenta en nuestro código y yo, personalmente, no quiero hacer eso;)


Nota:

ES2015 introduce un nuevo método de comparación, Object.is. Object.isdistingue explícitamente entre -0y +0:

Object.is(-0, +0); // false

15
De hecho 1/0 === Infinity; // truey 1/-0 === -Infinity; // true.
user113716

48
Entonces tenemos 1 === 1y +0 === -0pero 1/+0 !== 1/-0. ¡Que raro!
Randomblue

8
@Random: Creo que ciertamente es mejor que +0 !== -0;) Eso realmente podría crear problemas.
Felix Kling

@FelixKling, o 0 !== +0/ 0 !== -0, lo que de hecho también crearía problemas.
Yanick Rochon

55
En realidad, este comportamiento limita el cálculo en matemáticas. Por ejemplo, la función 1 / x tiene un valor infinito en 0, sin embargo, se separa si nos acercamos a 0 desde el lado positivo del negativo; en el primero, el resultado es + inf, en el segundo, -inf.
Agoston Horvath

19

Agregaré esto como respuesta porque pasé por alto el comentario de @ user113716.

Puede probar para -0 haciendo esto:

function isMinusZero(value) {
  return 1/value === -Infinity;
}

isMinusZero(0); // false
isMinusZero(-0); // true

66
Probablemente también debería verificar == 0, ¡lo anterior esMinusZero (-1e-323) devuelve verdadero!
Chris

1
@Chris, el límite del exponente de doble precisión es que e±308su número solo puede representarse en forma desnormalizada y las diferentes implementaciones tienen diferentes opiniones sobre dónde apoyarlas o no. El punto es que, en algunas máquinas en algunos modos de coma flotante, su número se representa como -0y en otras como número desnormalizado 0.000000000000001e-308. Tales carrozas, tan divertido
Debilnespase

Esto también puede funcionar para otros idiomas (probé para C y esto funciona)
Mukul Kumar

12

Acabo de encontrar un ejemplo donde +0 y -0 se comportan de manera muy diferente:

Math.atan2(0, 0);  //returns 0
Math.atan2(0, -0); //returns Pi

Tenga cuidado: incluso cuando use Math.round en un número negativo como -0.0001, en realidad será -0 y puede arruinar algunos cálculos posteriores como se muestra arriba.

Una forma rápida y sucia de solucionar esto es hacer algo como:

if (x==0) x=0;

o solo:

x+=0;

Esto convierte el número a +0 en caso de que fuera -0.


Gracias. Tan extraño cómo agregar cero solucionaría el problema que encontré. "Si todo lo demás falla, agregue cero". Una lección para la vida.
Microsis el

También encontré esto en Math.atan (y / x), que (quizás sorprendentemente) puede manejar infinitamente o negativamente "y / x", excepto que da la respuesta incorrecta en el caso en que x es -0. Reemplazar "x" con "(x + 0)" lo arregla.
Jacob C. dice Restablecer a Mónica el

5

En el estándar IEEE 754 utilizado para representar el tipo de Número en JavaScript, el signo está representado por un bit (un 1 indica un número negativo).

Como resultado, existe un valor tanto negativo como positivo para cada número representable, incluido 0.

Esta es la razón por tanto -0y +0existir.


3
El complemento a dos también usa un bit para el signo, pero solo tiene un cero (positivo).
Felix Kling

1
Sí, pero en el complemento de Two, el bit negativo también es parte del valor, por lo que una vez que configura el bit negativo, ya no es cero.
Arnaud Le Blanc

3

Respondiendo el título original Are +0 and -0 the same?:

brainslugs83(en comentarios de respuesta por Spudley) señaló un caso importante en el que +0 y -0 en JS no son lo mismo, implementado como función:

var sign = function(x) {
    return 1 / x === 1 / Math.abs(x);
}

Esto, además del estándar, Math.signdevolverá el signo correcto de +0 y -0.


2

Hay dos valores posibles (representaciones de bits) para 0. Esto no es único. Especialmente en números de coma flotante esto puede ocurrir. Esto se debe a que los números de coma flotante se almacenan realmente como una especie de fórmula.

Los enteros también se pueden almacenar por separado. Puede tener un valor numérico con un bit de signo adicional, por lo que en un espacio de 16 bits, puede almacenar un valor entero de 15 bits y un bit de signo. En esta representación, el valor 1000 (hexadecimal) y 0000 son ambos 0, pero uno de ellos es +0 y el otro es -0.

Esto podría evitarse restando 1 del valor entero para que oscilara entre -1 y -2 ^ 16, pero esto sería inconveniente.

Un enfoque más común es almacenar números enteros en 'dos ​​complementos', pero aparentemente ECMAscript ha elegido no hacerlo. En este método, los números varían de 0000 a 7FFF positivo. Los números negativos comienzan en FFFF (-1) a 8000.

Por supuesto, las mismas reglas se aplican también a los enteros más grandes, pero no quiero que mi F se desgaste. ;)


44
Pero no te parece +0 === -0un poco raro. Porque ahora tenemos 1 === 1y +0 === -0pero 1/+0 !== 1/-0...
Randomblue

2
Por supuesto, +0 es -0. No es nada. Pero hay una gran diferencia entre + infinito y -infinito, ¿existe? Esos números de infinito pueden incluso ser la razón por la cual ECMA admite tanto +0 como -1.
GolezTrol

No explica por qué a +0 === -0pesar de que las representaciones de dos bits son diferentes.
Randomblue

1
+0 es -0 es 0, nada, nada, niente. Tiene sentido que sean iguales. ¿Porque el cielo es azul? 4 + 3 también es lo mismo que 1 + 6, aunque las representaciones son diferentes. Tienen representaciones diferentes (y, por lo tanto, un valor de bit diferente), pero cuando se comparan, se manejan como el mismo cero, que son.
GolezTrol

1
No son lo mismo. Consulte stackoverflow.com/questions/7223717/differentiating-0-and-0 para ver ejemplos que lo demuestran.
Randomblue

2

Podemos utilizar Object.ispara distinguir 0 y -0, y una cosa más, NaN==NaN.

Object.is(+0,-0) //false

Object.is(NaN,NaN) //true

1

Lo culparía del método de comparación estricta de igualdad ('==='). Mira la sección 4d ingrese la descripción de la imagen aquí

ver 7.2.13 Comparación estricta de igualdad en la especificación


0

Wikipedia tiene un buen artículo para explicar este fenómeno: http://en.wikipedia.org/wiki/Signed_zero

En resumen, tanto +0 como -0 se definen en las especificaciones de coma flotante IEEE. Ambos son técnicamente distintos de 0 sin signo, que es un número entero, pero en la práctica todos se evalúan a cero, por lo que la distinción puede ignorarse a todos los efectos prácticos.


2
Eso no es del todo correcto: 1 / -0 == 1/0 se evalúa como falso en javascript, por ejemplo. No "evalúan" a un cero mágico sin signo, ya que no existe un concepto tal como "un cero entero sin signo" en IEEE 754.
BrainSlugs83
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.