Math.Max(1f, float.NaN) == NaN
new[] { 1f, float.NaN }.Max() == 1f
为什么?
编辑:双倍也有同样的问题!
他还在这条后续推文中解释了原因:
这是因为扩展方法使用(并且被记录为使用)IComparable 的实现,它将任何东西都比较为> NaN。
正如其他人所发布的那样,我在推特上发布了一种“为什么”——因为它是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 与其他的相对排序。
(正确)答案的一个补充说明:即使您只阅读了简单的解释,两者的行为也都如文件所述。
此 IEnumerable 上的 Max() 扩展:
返回 Single 值序列中的最大值。
和 Math.Max():
[返回] 参数 val1 或 val2,以较大者为准。如果 val1、val2 或 val1 和 val2 都等于 NaN,则返回 NaN。
注意 NaN 不是一个值——所以可枚举的 Max 总是返回最大值。Math.Max 返回两个值中的较大者,如果其中一个或两个都是 NaN,则返回 NaN。
如果您将 NaN 作为参数传递,则 Math.max 方法专门设计为返回 NaN。请注意,这意味着 Math.max(a, b) 可以返回一个不大于任一参数的值;将 NaN 与任何运算符与任何其他值进行比较都会产生 false。
在数组上使用 .Max() 时,默认实现(我相信)会扫描列表以查找比较大于任何其他值的值。由于 NaN 从不比较大于任何值,因此函数不会选择它。
简而言之,我认为您的问题的答案是 Math.Max 很奇怪,而扩展方法 Max 是正确的。
其他人已经发布了 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。
我想 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。