Math.Max vs Enumerable.Max

时间:2011-01-08 20:18:45

标签: .net math floating-point double nan

Jon Skeet今天(source)报告:

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

为什么?

编辑:同样的问题也有双倍!

6 个答案:

答案 0 :(得分:5)

他还在this后续推文中解释了原因:

  

这是因为扩展方法使用(并记录使用)IComparable的实现,它将任何内容与>进行比较。为NaN。

答案 1 :(得分:4)

正如其他人发布的那样,我发布了一个类型的“为什么” - 因为它正在使用IComparable作为记录。

这只会导致另一个“为什么”。特别是:

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

第一行表明NaN被认为大于0.第二行表明0被认为大于NaN。 (当然,这些都不能报告“这种比较没有意义”的结果。)

我看到所有回复推文的优势当然包括these two

  

这看似不寻常,但这是正确的答案。如果所有元素都是NaN,则数组的max()为NaN。见IEEE 754r。

     

此外,Math.Max使用IEEE 754r总排序谓词,该谓词指定NaN与其他人的相对排序。

答案 2 :(得分:2)

(正确的)答案的一个补充说明:即使您只阅读简单的解释,两者都表现得有记录。

此IEnumerable上的Max()扩展名:

  

返回a中的最大值   单值序列。

和Math.Max():

  

[返回]参数val1或val2,   以较大者为准。如果val1,val2或   val1和val2都等于NaN,   NaN被退回。

请注意,NaN不是值 - 因此可枚举的Max总是返回最大的。 Math.Max返回两个值中较大的一个,如果其中一个或两个都是NaN,则返回NaN。

答案 3 :(得分:1)

如果您将NaN作为参数传递,Math.max方法专门用于返回NaN。请注意,这意味着Math.max(a,b)可以返回一个不大于任一参数的值; NaN与任何运算符相比,任何其他值都会产生错误。

在数组上使用.Max()时,默认实现(我相信)会扫描列表,查找比任何其他值更大的值。由于NaN从不比任何东西都要好,因此函数不会选择它。

简而言之,我认为你的问题的答案是Math.Max很奇怪,而扩展方法Max正确的做法。

答案 4 :(得分:0)

其他人已经发布了John发布的答案(扩展方法使用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。

答案 5 :(得分: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;

如果任何参数为none,它将返回。

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

而且,如果任何参数是Nan,那么正确实现max总是返回b。