2011-01-08 5 views
9

Jon Skeet rapporti oggi (source) che:Math.max vs Enumerable.Max

Math.Max(1f, float.NaN) == NaN 
new[] { 1f, float.NaN }.Max() == 1f 

Perché?

Modifica: stesso numero con doppio anche!

+0

Link a dove viene segnalato questo? –

+0

@matt: il suo account Twitter, @jonskeet –

+2

'Max' è un metodo di estensione fornito da' Enumerable' contro 'IEnumerable ', non proviene da 'Array'. –

risposta

4

Come altri hanno pubblicato, ho twittato uno una sorta di "perché" - nel senso che sta usando IComparable come documentato.

Questo porta solo a un altro "perché".In particolare:

Console.WriteLine(Math.Max(0, float.NaN)); // Prints NaN 
Console.WriteLine(0f.CompareTo(float.NaN)); // Prints 1 

La prima riga indica che NaN è considerata maggiore di 0. La seconda linea indica che 0 è considerata superiore NaN. (Nessuno di questi può segnalare il risultato di "questo confronto non ha senso", naturalmente.)

ho il vantaggio di vedere tutti i tweet di risposta, naturalmente, tra cui thesetwo:

Può sembrare insolito, ma questa è la risposta giusta. max() di un array è NaN se tutti gli elementi sono NaN. Vedi IEEE 754r.

Inoltre, Math.Max ​​utilizza il predicato di ordinamento totale IEEE 754r, che specifica l'ordine relativo di NaN rispetto ad altri.

+0

@john: grazie john –

+0

la domanda è che il team C# dovrebbe occuparsi di questo tipo di risultati inaspettati? –

+0

@HPT: il team C# non ha nulla a che fare con esso - è una domanda di libreria. Ma fondamentalmente sospetto che molte persone (me compreso) sarebbero sorprese da qualsiasi numero di cose su NaN. –

5

Ha anche spiegato il motivo per cui in this follow-up Tweet:

è perché l'utilizza il metodo di estensione (ed è documentata da usare) l'attuazione di IComparable, che confronta nulla come> NaN.

0

Altri hanno inviato la risposta che Giovanni ha pubblicato (il metodo di estensione utilizza IComparable che restituisce nulla come> allora NaN), ed usando il riflettore a guardare l'attuazione di Math.max mostra questa

public static double Max(double val1, double val2) 
{ 
    if (val1 > val2) 
    { 
     return val1; 
    } 
    if (double.IsNaN(val1)) 
    { 
     return val1; 
    } 
    return val2; 
} 

Quindi puoi capire perché restituiscono risultati diversi. Se esegui (1.0> double.NaN) restituirà false.

1

Il metodo Math.max è specificamente progettato per restituire NaN se si passa NaN come argomento. Nota che ciò significa che è possibile per Math.max (a, b) restituire un valore che non è maggiore di entrambi gli argomenti; NaN confrontato con qualsiasi operatore con qualsiasi altro valore falso.

Quando si utilizza .Max() sull'array, l'implementazione predefinita (credo) scansiona l'elenco alla ricerca del valore che confronta maggiore di qualsiasi altro valore. Dal momento che NaN non confronta mai più di ogni altra cosa, non verrà scelto dalla funzione.

In breve, penso che la risposta alla tua domanda sia che Math.Max ​​è strano, mentre il metodo di estensione Max sta facendo bene.

2

Un'aggiunta alle risposte (corrette) dichiarate: Entrambi si comportano come documentati, anche se si legge solo la semplice spiegazione.

Max() estensione su questo IEnumerable:

Restituisce il valore massimo in una sequenza di valori Single .

e Math.max():

[Returns] val1 Parametro o val2, se superiore. Se val1, val2 o sia val1 che val2 sono uguali a NaN, NaN viene restituito.

Nota che NaN non è un valore - in modo che il enumerabile Max restituisce sempre il valore più grande. Math.Max ​​restituisce il maggiore di due valori, o NaN se uno o entrambi sono NaN.

0

Suppongo che se 1 o Nan sia maggiore non è definito da alcuno standard, quindi è lasciato all'implementazione decidere questo. Si noti che tutte queste dichiarazioni producono falso:

 Console.WriteLine("1>Nan {0}]", 1.0 > double.NaN); 
     Console.WriteLine("1<Nan {0}]", 1.0 < double.NaN); 
     Console.WriteLine("1>=Nan {0}]", 1.0 >= double.NaN); 
     Console.WriteLine("1<=Nan {0}]", 1.0 <= double.NaN); 

Quindi, se Max() è definito come:

if (a<=b) return b else return a; 

verrà restituito un se uno qualsiasi degli argomenti è nessuno.

if (a>b) return a else return b; 

E questo, anche l'implementazione corretta di max restituisce sempre b se uno qualsiasi degli argomenti è Nan.