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:他的推特账号@jonskeetMax
是Enumerable
针对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 意外行为
Math.min() Math.max() Math.min().apply() Math.max() .apply()该如何使用???
JavaScript中Math.max.apply()和Math.max()的区别