Math.Max 与 Enumerable.Max

Posted

技术标签:

【中文标题】Math.Max 与 Enumerable.Max【英文标题】:Math.Max vs Enumerable.Max 【发布时间】:2011-06-05 21:00:15 【问题描述】:

Jon Skeet 今天报告 (source):

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

为什么?

编辑:double 也有同样的问题!

【问题讨论】:

链接到他报告的地方? @matt:他的推特账号@jonskeet MaxEnumerable针对IEnumerable<T>提供的扩展方法,它并非来自Array Also, Math.Max uses IEEE 754r total ordering predicate, which specifies relative ordering of NaN vs. others. 我认为1或Nan更大没有任何标准定义,所以由实现来决定。 【参考方案1】:

我认为 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;

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

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

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

【讨论】:

【参考方案2】:

正如其他人所发布的那样,我在推特上发布了一个之类的“为什么”——因为它使用了IComparable,正如所记录的那样。

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

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

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

我的优势是看到所有回复推文,当然包括thesetwo:

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

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

【讨论】:

问题是C#团队应该照顾这种意想不到的结果吗? @HPT:C# 团队与此无关 - 这是一个库问题。但从根本上说,我怀疑大多数人(包括我自己)会对 NaN 的许多事情感到惊讶。 @john:我犯了一个错误,我的意思是 .Net 团队。 @HPT:对。但我仍然认为这只是 NaN 具有根本上意想不到的行为的问题 - 如果您详细研究所有内容,这无疑是有道理的,但是当您只考虑一些个别情况时看起来很奇怪。并且不要忘记 .NET 团队不对 IEEE 754 本身负责:)【参考方案3】:

对(正确)答案的补充说明:即使您只阅读了简单的解释,两者的行为都与记录相同。

此 IEnumerable 上的 Max() 扩展:

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

和 Math.Max():

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

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

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

【参考方案5】:

其他人已经发布了 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。

【讨论】:

【参考方案6】:

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

这是因为扩展方法使用(并且被记录为使用)IComparable 的实现,它将任何东西都比较为 > NaN。

【讨论】:

以上是关于Math.Max 与 Enumerable.Max的主要内容,如果未能解决你的问题,请参考以下文章

Apache Spark Reduce 与 java.lang.Math.max 意外行为

javascript中Math函数的属性与方法

Math.min() Math.max() Math.min().apply() Math.max() .apply()该如何使用???

JavaScript中Math.max.apply()和Math.max()的区别

Math.max(a,b) or (a>b)?a:b 在 Java 中更快吗?

javascript Math.min Math.max