2011-01-08 2 views
9

Jon Skeet сообщает сегодня (source), что:Math.max против Enumerable.Max

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

Почему?

Редактировать: та же проблема с двойным также!

+0

Ссылка на то, где он сообщает об этом? –

+0

@matt: его учетная запись Twitter, @jonskeet –

+2

'Max' - это метод расширения, предоставляемый' Enumerable' против 'IEnumerable ', это не из 'Array'. –

ответ

4

Как и другие, я написал твиттер один вид «почему» - в том, что он использует IComparable как задокументировано.

Это просто приводит к другому «почему».В частности:

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

Первая строка указывает, что NaN рассматривается как больше 0. Вторая строка показывает, что 0 рассматривается как более NaN. (Ни один из них может сообщить результат «это сравнение не имеет смысла», конечно.)

У меня есть преимущество видеть все отклики твиты, конечно, в том числе thesetwo:

Это может показаться необычным, но это правильный ответ. max() массива NaN, если все элементы являются NaN. См. IEEE 754r.

Кроме того, Math.Max ​​использует общий предикат порядка IEEE 754r, который определяет относительное упорядочение NaN и других.

+0

@john: спасибо john –

+0

вопрос должен ли C# команда позаботиться о таких неожиданных результатах? –

+0

@ HPT: Команда C# не имеет к этому никакого отношения - это вопрос библиотеки. Но в принципе я подозреваю, что большинство людей (включая меня) были бы удивлены любым количеством вещей о NaN. –

5

Он также объяснил причину, почему в this последующих твиттере:

Это потому, что метод расширения использует (и документированные использовать) осуществление IComparable, который сравнивает ничего, как> NaN.

0

Другие опубликовали ответ, который отвечал Джон (метод расширения использует IComparable, который возвращает ничего, как> то NaN), и с помощью отражателя, чтобы посмотреть на реализацию Math.max показывает, что это

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

Поэтому вы можете понять, почему они возвращают разные результаты. Если вы запустите (1.0> double.NaN), он вернет false.

1

Метод Math.max специально разработан для возврата NaN, если вы передадите NaN в качестве аргумента. Обратите внимание, что это означает, что Math.max (a, b) может возвращать значение, не превышающее любой аргумент; NaN по сравнению с любым оператором для любого другого значения дает false.

При использовании .Max() в массиве реализация по умолчанию (я считаю) просматривает список, ищущий значение, которое сравнивается больше любого другого значения. Поскольку NaN никогда не сравнивается больше чем что-либо, он не будет выбран функцией.

Короче говоря, я думаю, что ответ на ваш вопрос заключается в том, что Math.Max ​​странный, в то время как метод расширения Max делает все правильно.

2

Одно из утверждений (правильных) ответов: Оба ведут себя как задокументированные, даже если вы читаете простое объяснение.

Max() расширение на этом IEnumerable:

Возвращает максимальное значение в последовательности единичных значений.

и Math.max():

[Возврат] Параметр знач1 или знач2, ​​ в зависимости от того, больше. Если val1, val2 или оба значения val1 и val2 равны NaN, возвращается NaN.

Обратите внимание, что NaN не является значением - так перечислимы Макс всегда возвращает наибольшее значение . Math.Max ​​возвращает большее из двух значений, или NaN, если один или оба из них являются NaN.

0

Я полагаю, что если 1 или 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); 
     Console.WriteLine("1<=Nan {0}]", 1.0 <= double.NaN); 

Так что, если Max() определяется как:

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

будет возвращать, если какой-либо из аргументов нет.

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

И это, также правильная реализация max всегда возвращает b, если любой из аргументов является Nan.

Смежные вопросы