The Math.max method is specifically designed to return NaN if you pass NaN as an argument. Note that this means that it's possible for Math.max(a, b) to return a value that isn't greater than either argument; NaN compared with any operator to any other value yields false.
When using .Max() on the array, the default implementation (I believe) scans over the list looking for the value that compares greater than any other value. Since NaN never compares greater than anything, it won't be chosen by the function.
In short, I think the answer to your question is that Math.Max is weird, whereas the extension method Max is getting it right.
I suppose that whether 1 or Nan is greater is not defined by any standard, so it is left to the implementation to decide this. Note that all these statements produce false:
Others have posted the answer that John posted (the extension method uses IComparable which returns anything as > then NaN), and using reflector to look at the implementation of Math.Max shows this
public static double Max(double val1, double val2)
{
if (val1 > val2)
{
return val1;
}
if (double.IsNaN(val1))
{
return val1;
}
return val2;
}
So you can see why they return different results. If you run (1.0 > double.NaN) it will return false.
One addition to the (correct) answers stated: Both behave as documented, even if you read the simple explanation only.
Max() extension on this IEnumerable:
Returns the maximum value in a
sequence of Single values.
and Math.Max():
[Returns] Parameter val1 or val2,
whichever is larger. If val1, val2, or
both val1 and val2 are equal to NaN,
NaN is returned.
Note that NaN is not a value - so the enumerable Max always returns the largest value. Math.Max returns the greater of two values, or NaN if either or both of them is NaN.
As others have posted, I tweeted one sort of "why" - in that it's using IComparable as documented.
That just leads to another "why" though. In particular:
Console.WriteLine(Math.Max(0, float.NaN)); // Prints NaN
Console.WriteLine(0f.CompareTo(float.NaN)); // Prints 1
The first line suggests that NaN is regarded as being greater than 0. The second line suggests that 0 is regarded as being greater than NaN. (Neither of these can report the result of "this comparison doesn't make sense", of course.)
I have the advantage of seeing all the reply tweets, of course, including thesetwo:
It may seem unusual, but that's the right answer. max() of an array is NaN iff all elements are NaN. See IEEE 754r.
Also, Math.Max uses IEEE 754r total ordering predicate, which specifies relative ordering of NaN vs. others.
The Math.max method is specifically designed to return NaN if you pass NaN as an argument. Note that this means that it's possible for Math.max(a, b) to return a value that isn't greater than either argument; NaN compared with any operator to any other value yields false.
When using .Max() on the array, the default implementation (I believe) scans over the list looking for the value that compares greater than any other value. Since NaN never compares greater than anything, it won't be chosen by the function.
In short, I think the answer to your question is that Math.Max is weird, whereas the extension method Max is getting it right.
He also explained the reason why in this follow-up tweet:
I suppose that whether 1 or Nan is greater is not defined by any standard, so it is left to the implementation to decide this. Note that all these statements produce false:
So if
Max()
is defined as:it will return a if any of the arguments is none.
And this, also correct implementation of max always return b if any of the arguments is Nan.
Others have posted the answer that John posted (the extension method uses IComparable which returns anything as > then NaN), and using reflector to look at the implementation of Math.Max shows this
So you can see why they return different results. If you run (1.0 > double.NaN) it will return false.
One addition to the (correct) answers stated: Both behave as documented, even if you read the simple explanation only.
Max() extension on this IEnumerable:
and Math.Max():
Note that NaN is not a value - so the enumerable Max always returns the largest value. Math.Max returns the greater of two values, or NaN if either or both of them is NaN.
As others have posted, I tweeted one sort of "why" - in that it's using
IComparable
as documented.That just leads to another "why" though. In particular:
The first line suggests that NaN is regarded as being greater than 0. The second line suggests that 0 is regarded as being greater than NaN. (Neither of these can report the result of "this comparison doesn't make sense", of course.)
I have the advantage of seeing all the reply tweets, of course, including these two: