Math.Max与Enumerable.Max的区别

9

Jon Skeet reports today (source) that :

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

为什么?
编辑:双倍也存在相同的问题!

他报告这个问题的链接在哪里? - Matt Ball
@matt:他的 Twitter 账号,@jonskeet - user415789
2
Maxوک¯ç”±Enumerableوڈگن¾›çڑ„é’ˆه¯¹IEnumerable<T>çڑ„و‰©ه±•و–¹و³•ï¼Œه®ƒه¹¶ن¸چو‌¥è‡ھن؛ژArrayم€‚ - Anthony Pegram
1
另外,Math.Max使用IEEE 754r总序谓词,该谓词指定NaN与其他值的相对顺序。 - moinudin
我认为1和Nan哪个更大并没有被任何标准定义,因此这取决于实现来决定。 - codymanix
6个回答

5
他还解释了后续推文中的原因:
这是因为扩展方法使用(并记录为使用)IComparable的实现,该实现将任何内容与NaN进行比较。

4

正如其他人所发表的,我在推特上发布了一个关于“为什么”的问题——因为它使用了文档中记录的 IComparable 接口。

然而,这只是另一个“为什么”的引子。具体来说:

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

第一行表示NaN被认为大于0。第二行表示0被认为大于NaN。(当然,这两者都不能报告“这种比较没有意义”的结果。)
我有一个优势,可以看到所有的回复推文,包括这两个:这个那个

这可能看起来不寻常,但这是正确的答案。如果数组中所有元素都是NaN,则数组的max()也是NaN。参见IEEE 754r。

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


问题是C#团队是否应该处理这种意外结果? - user415789
@HPT:C#团队与此无关 - 这是一个库的问题。但从根本上说,我怀疑大多数人(包括我自己)对NaN的许多事情都会感到惊讶。 - Jon Skeet
@john:我犯了一个错误,我的意思是 .Net 团队。 - user415789
@HPT:没错。但我仍然认为NaN具有根本上意外的行为——如果你只考虑一些个别情况,这无疑是有道理的,但当你深入研究时,它看起来很奇怪。而且不要忘记,.NET团队并不负责IEEE 754本身 :) - Jon Skeet

2

在正确答案的基础上,还有一个补充:即使只阅读简单说明,两者行为均符合文档。

针对此 IEnumerable 的 Max() 扩展:

返回序列中的 Single 值的最大值。

而 Math.Max():

返回参数 val1 或 val2 中较大的那个。如果 val1、val2 或 val1 和 val2 都等于 NaN,则返回 NaN。

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


1

Math.max方法是专门设计的,如果您将NaN作为参数传递,则返回NaN。请注意,这意味着Math.max(a, b)可能返回一个不大于任何一个参数的值;NaN与任何其他值的任何运算符比较都会得到false。

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

简而言之,我认为您问题的答案是Math.Max很奇怪,而扩展方法Max则做得很好。


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。


0

我认为1和NaN哪个更大并没有被任何标准定义,所以这取决于实现来决定。请注意,所有这些语句都会产生false:

        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,则它将返回a。

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

而且,如果任何一个参数为 NaN,则 max 的正确实现总是返回 b。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接