2013-01-22 12 views
36

Sono bloccato cercando di scoprire il motivo per cui queste due operazioni restituiscono valori diversi:Confrontando Double.NaN con se stessa

  1. Double.NaN == Double.NaN rendimenti false
  2. Double.NaN.Equals(Double.NaN) restituisce true

ho il answer a la prima parte ma non la seconda e non "perché questi due confronti restituiscono valori diversi"

+2

Potrebbe essere un commento stupido, ma direi che nel caso 1, si confrontano i valori. E nel caso 2 stai confrontando i riferimenti. – jbl

+4

@jbl No, stai confrontando i valori in entrambi i casi - 'double's non sono riferimenti e non sei nemmeno in boxing da [' System.Double.Equals'] (http://msdn.microsoft.com/ en-us/library/ya2zha7s.aspx) è sovraccarico. –

+0

@spender OMFG Dovrei leggere meglio la domanda! Grazie! –

risposta

30

Il motivo della differenza è semplice, se non evidente.

Se si utilizza l'operatore di uguaglianza ==, si sta utilizzando il test IEEE per l'uguaglianza.

Se si utilizza il metodo Equals(object), è necessario mantenere il contratto di object.Equals(object). Quando si implementa questo metodo (e il corrispondente metodo GetHashCode), è necessario mantenere tale contratto, che è diverso dal comportamento IEEE.

Se il contratto Equals non è stato confermato, il comportamento delle tabelle hash si interrompe.

var map = new Dictionary<double,string>(); 
map[double.NaN] = "NaN"; 
var s = map[double.NaN]; 

Se !double.NaN.Equals(double.NaN), non otterresti mai il tuo valore fuori dal dizionario!

Se la frase precedente non ha senso, quindi capire che la meccanica di hashing (utilizzati in Dictionary<T,U>, HashSet<T>, ecc) utilizzano sia le object.Equals(object) e object.GetHashCode() metodi ampiamente, e contare su garanzie del loro comportamento.

+1

Ah. Finalmente. :-) (Mi piacerebbe molto ottenere un riferimento corretto per la richiesta qui, ma credo che questa sia la risposta corretta (la parte contrattuale è sicuramente), quindi +1). –

+1

Sì, dovrei sottolineare che non ho un riferimento. È solo l'unica ragione che ha senso per me. –

+1

+1. Potete fornire un riferimento al test IEEE per l'uguaglianza? Non ho potuto trovarlo da nessuna parte – GETah

9

Nella parte inferiore della sezione osservazioni di Double.Equals, troverete:

Se due valori Double.NaN sono testati per l'uguaglianza chiamando il metodo Equals, il metodo restituisce true. Tuttavia, se due valori NaN vengono testati per l'uguaglianza utilizzando l'operatore di uguaglianza, l'operatore restituisce false. Quando si desidera determinare se il valore di un doppio non è un numero (NaN), un'alternativa è chiamare il metodo IsNaN.

+2

Mi chiedo se c'è un motivo al di là _del documento dice così_ :) –

+0

Grazie per la risposta rapida. Sai perché questa differenza? – GETah

+4

Questo non risponde alla parte "perché" della domanda. – ken2k

3

se si ispeziona Double.NaN;

// Summary: 
    //  Represents a value that is not a number (NaN). This field is constant. 
    public const double NaN = 0.0/0.0; 

il primo restituisce falso poiché NaN non rappresenta alcun numero.

Un metodo o operatore restituisce NaN quando il risultato di un'operazione è indefinito. Ad esempio, il risultato della divisione per zero a zero è NaN

Il secondo restituisce vero come NaN uguaglianza è implementato esplicitamente nel equals metodo di overload.

da msdn double.equals:

Se due valori Double.NaN sono testati per l'uguaglianza chiamando Eguali metodo, il metodo restituisce true. Tuttavia, se vengono testati due valori NaN per l'uguaglianza utilizzando l'operatore di uguaglianza, l'operatore restituisce false. Quando si desidera determinare se il valore di una doppia non è un numero (NaN), un'alternativa è chiamare il metodo IsNaN.

Questo è fatto delibaretly per conformarsi a IEC 60559:1989;

Secondo IEC 60559: 1989, due numeri in virgola mobile con valori di NaN sono mai equal.However, secondo le specifiche per l'System.Object :: Eguali metodo, è desiderabile sovrascrivere questo metodo per fornire il valore semantica dell'uguaglianza. Poiché System.ValueType fornisce questa funzionalità attraverso l'uso di Reflection, la descrizione per Object.Equals specifica che i tipi di valore dovrebbero considerare sovrascrivendo l'implementazione ValueType predefinita per ottenere un aumento delle prestazioni . Infatti, dall'origine di System.ValueType :: Equals (riga 36 di clr \ src \ BCL \ System \ ValueType.cs in SSCLI), c'è persino un commento dal team CLR Perf all'effetto di System.ValueType :: Uguale a non essere veloce.

si riferiscono a: http://blogs.msdn.com/b/shawnfa/archive/2004/07/19/187792.aspx

+2

La domanda era ** perché ** i due metodi hanno dato risultati diversi. Non hai risposto a questo. –

+0

Credo di aver risposto; NaN non è definito, non rappresenta alcun numero, non è definito. Parlare di uguaglianza non è possibile; ma il metodo equals definisce un'uguaglianza tra due valori NaN. – daryal

+2

* Perché * è uguale a 'Equals' come questo? Stai semplicemente [elemosinando la domanda] (https://en.wikipedia.org/wiki/Begging_the_question). –

3

Beh, Oded's answer è grande, ma voglio dire qualcosa;

Quando decompilo il metodo Double.Equals(), sembra così;

public bool Equals(double obj) 
{ 
    return ((obj == this) || (IsNaN(obj) && IsNaN(this))); 
} 

Quindi, dal momento che abbiamo questo = Double.NaN e obj = Double.NaN

(IsNaN(obj)) and (IsNaN(this)) returns `true`. 

Quindi, fondamentalmente, è possibile return ((obj == this) || true

che è equvalent a

return ((obj == this) è true.

+3

+1. Ora mi sto confondendo: p – GETah

+1

E ancora una volta si tratta solo di elemosinare la domanda. Sappiamo già * che 'Double.Equals' ha un trattamento speciale per NaN, la domanda è * perché *. –

+0

@KonradRudolph, spiego perché nella mia risposta. È a causa del contratto semantico che deve essere sostenuto. –