4

我需要在数组中找到最小值最大值(不考虑该数组中可能的NaN值)。

这很容易只使用double,但是这些 FindMin 和 FindMax 函数必须使用泛型类型。

我试图以这种方式测试通用NaN:

bool isNaN<T>(T value) where T : IEquatable<T>
{
    return !value.Equals(value);
}

但是Equals回来truedouble.NaN??!!

我现在有这样的解决方法:

bool isNaN<T>(T value) where T : IEquatable<T>
{
    var d = value as double?;
    if (d.HasValue) { return double.IsNaN(d.Value); }

    return !value.Equals(value);
}

我的问题更多是关于理解为什么第一个解决方案不起作用,这是一个错误吗?

你可以在这里找到小的测试代码

4

2 回答 2

7

我会简单地使用double.IsNaN并让编译器float在需要时隐式转换成员:

float myFloat = float.NaN; // or 0.0f / 0.0f;
double myDouble = double.NaN; // or 0.0 / 0.0;

Console.WriteLine(double.IsNaN(myFloat));
Console.WriteLine(double.IsNaN(myDouble));

“浪费”堆栈上的极少量内存并使用强制转换操作调用,但是嘿嘿,它足够通用,可以满足任何可以容纳“数字”NaN 的类型。

或者, usingfloat.IsNaN似乎可以与基本测试一起使用,但需要对 a 进行明确的向下转换double(向下转换double.NaN并且0.0 / 0.0似乎可以正常工作,如它NaN正确报告)。

您通常不能以任何清洁度(或者根本,我不是 100% 确定)限制值类型的子集,因此我不会费心<T>亲自追逐路线。


如果您想要一个通用解决方案,这意味着被调用者不需要关心传入的内容,您可以执行以下操作:

    static bool IsNaN(dynamic d)
    {
        float dub;

        try
        {
            dub = (float)d;
            return float.IsNaN(dub);
        }
        catch (RuntimeBinderException)
        {
        }

        return false;
    }

但是,这会引起拳击。另请注意,这dynamic是必需的并且object不起作用,因此这也会调用 DLR(并且还会吞下所有RuntimeBinderExceptions)。

于 2012-08-24T12:38:19.800 回答
6

但 Equals 为 double.NaN 返回 true

是的。它确实与泛型无关:

double x = double.NaN;
Console.WriteLine(x.Equals(x)); // True
Console.WriteLine(x == x); // False

请注意,如果第二行打印为 False,那将导致与覆盖IEquatable<T>.Equals不一致,或者您必须违反.Equals(object)Equals(object)object.Equals(object)

基本上这种事情是讨厌的,无论你用它做什么。

鉴于您正在尝试查找最大值/最小值,您可能想尝试使用IComparable<T>而不是IEquatable<T>- 这很可能让您以其他方式检测 NaN。(我现在没有时间检查。)

于 2012-08-24T12:27:00.983 回答