Leggendo la specifica ECMAScript 5.1 , +0
e -0
si distinguono.
Perché allora +0 === -0
valuta true
?
Object.is
per distinguere +0 e -0
Leggendo la specifica ECMAScript 5.1 , +0
e -0
si distinguono.
Perché allora +0 === -0
valuta true
?
Object.is
per distinguere +0 e -0
Risposte:
JavaScript utilizza lo standard IEEE 754 per rappresentare i numeri. Da Wikipedia :
Lo zero con segno è zero con un segno associato. Nell'aritmetica ordinaria, −0 = +0 = 0. Tuttavia, nel calcolo, alcune rappresentazioni numeriche consentono l'esistenza di due zeri, spesso indicati con −0 (zero negativo) e +0 (zero positivo) . Ciò si verifica in alcune rappresentazioni di numeri con segno per numeri interi e nella maggior parte delle rappresentazioni di numeri in virgola mobile. Il numero 0 è generalmente codificato come +0, ma può essere rappresentato da +0 o −0.
Lo standard IEEE 754 per l'aritmetica in virgola mobile (attualmente utilizzato dalla maggior parte dei computer e dei linguaggi di programmazione che supportano i numeri in virgola mobile) richiede sia +0 che −0. Gli zeri possono essere considerati una variante della riga del numero reale esteso in modo tale che 1 / −0 = −∞ e 1 / + 0 = + ∞, la divisione per zero non è definita solo per ± 0 / ± 0 e ± ∞ / ± ∞ .
L'articolo contiene ulteriori informazioni sulle diverse rappresentazioni.
Quindi questo è il motivo per cui, tecnicamente, entrambi gli zeri devono essere distinti.
Tuttavia,
+0 === -0
restituisce true. Perché (...) ?
Questo comportamento è esplicitamente definito nella sezione 11.9.6 , l' algoritmo di confronto sull'uguaglianza rigorosa (l'enfasi è in parte mia):
Il confronto
x === y
, dovex
ey
sono valori, produce vero o falso . Tale confronto viene eseguito come segue:(...)
Se Tipo (x) è Numero, allora
- Se x è NaN, restituisce false.
- Se y è NaN, restituisce false.
- Se x ha lo stesso valore numerico di y, restituisce true.
- Se x è +0 e y è −0, restituisce true.
- Se x è −0 e y è +0, restituisce true.
- Restituisci falso.
(...)
(Lo stesso vale per +0 == -0
btw.)
Sembra logicamente da trattare +0
e -0
uguale. Altrimenti dovremmo tenerne conto nel nostro codice e, personalmente, non voglio farlo;)
Nota:
ES2015 introduce un nuovo metodo di confronto, Object.is
. Object.is
distingue esplicitamente tra -0
e +0
:
Object.is(-0, +0); // false
1/0 === Infinity; // true
e 1/-0 === -Infinity; // true
.
1 === 1
e +0 === -0
ma 1/+0 !== 1/-0
. Che strano!
+0 !== -0
;) Questo potrebbe davvero creare problemi.
0 !== +0
/ 0 !== -0
, che creerebbe davvero anche problemi!
Aggiungerò questo come risposta perché ho trascurato il commento di @utente113716.
Puoi provare per -0 in questo modo:
function isMinusZero(value) {
return 1/value === -Infinity;
}
isMinusZero(0); // false
isMinusZero(-0); // true
e±308
, il tuo numero può essere rappresentato solo in forma denormalizzata e diverse implementazioni hanno opinioni diverse su dove supportarle o meno. Il punto è che su alcune macchine in alcune modalità a virgola mobile il tuo numero è rappresentato come -0
e su altri come numero denormalizzato 0.000000000000001e-308
. Tali carri allegorici, così divertenti
Ho appena trovato un esempio in cui +0 e -0 si comportano in modo molto diverso:
Math.atan2(0, 0); //returns 0
Math.atan2(0, -0); //returns Pi
Fai attenzione: anche quando usi Math.round su un numero negativo come -0.0001, sarà effettivamente -0 e può rovinare alcuni calcoli successivi come mostrato sopra.
Un modo rapido e sporco per risolvere questo problema è fare smth come:
if (x==0) x=0;
o semplicemente:
x+=0;
Questo converte il numero in +0 nel caso in cui fosse -0.
Nello standard IEEE 754 utilizzato per rappresentare il tipo Numero in JavaScript, il segno è rappresentato da un bit (un 1 indica un numero negativo).
Di conseguenza, esiste un valore sia negativo che positivo per ciascun numero rappresentabile, incluso 0
.
Questo è il motivo per cui sia -0
e +0
esistono.
Rispondere al titolo originale Are +0 and -0 the same?
:
brainslugs83
(nei commenti della risposta di Spudley
) ha sottolineato un caso importante in cui +0 e -0 in JS non sono gli stessi - implementato come funzione:
var sign = function(x) {
return 1 / x === 1 / Math.abs(x);
}
Ciò, oltre allo standard, Math.sign
restituirà il segno corretto di +0 e -0.
Esistono due valori possibili (rappresentazioni di bit) per 0. Questo non è univoco. Ciò può verificarsi soprattutto nei numeri in virgola mobile. Questo perché i numeri in virgola mobile sono effettivamente memorizzati come un tipo di formula.
I numeri interi possono essere memorizzati anche in modi separati. È possibile avere un valore numerico con un bit di segno aggiuntivo, quindi in uno spazio di 16 bit è possibile memorizzare un valore intero di 15 bit e un bit di segno. In questa rappresentazione, il valore 1000 (esadecimale) e 0000 sono entrambi 0, ma uno di essi è +0 e l'altro è -0.
Ciò potrebbe essere evitato sottraendo 1 dal valore intero in modo che varia da -1 a -2 ^ 16, ma ciò sarebbe scomodo.
Un approccio più comune è quello di memorizzare numeri interi in "due complementi", ma apparentemente ECMAscript ha scelto di non farlo. In questo metodo i numeri vanno da 0000 a 7FFF positivi. I numeri negativi iniziano da FFFF (-1) a 8000.
Naturalmente, le stesse regole si applicano anche a numeri interi più grandi, ma non voglio che la mia F si esaurisca. ;)
+0 === -0
un po 'strano. Perché ora abbiamo 1 === 1
e +0 === -0
ma1/+0 !== 1/-0
...
+0 === -0
nonostante le due rappresentazioni dei bit siano diverse.
Darei la colpa al metodo del confronto rigoroso sull'uguaglianza ('==='). Guarda la sezione 4d
vedere 7.2.13 Confronto rigoroso di uguaglianza sulla specifica
Wikipedia ha un buon articolo per spiegare questo fenomeno: http://en.wikipedia.org/wiki/Signed_zero
In breve, sia +0 che -0 sono definiti nelle specifiche IEEE in virgola mobile. Entrambi sono tecnicamente distinti da 0 senza segno, che è un numero intero, ma in pratica valutano tutti a zero, quindi la distinzione può essere ignorata per tutti gli scopi pratici.