9

Jon Skeet今天报道(来源):

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

为什么?

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

4

6 回答 6

5

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

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

于 2011-01-08T20:27:22.003 回答
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 与其他的相对排序。

于 2011-01-08T20:37:44.250 回答
2

(正确)答案的一个补充说明:即使您只阅读了简单的解释,两者的行为也都如文件所述。

此 IEnumerable 上的 Max() 扩展:

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

和 Math.Max():

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

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

于 2011-01-08T20:36:10.670 回答
1

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

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

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

于 2011-01-08T20:34:35.197 回答
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。

于 2011-01-08T20:29:47.967 回答
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;

如果任何参数都没有,它将返回 a。

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

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

于 2011-01-08T20:38:04.540 回答