Question

I need to find min and max values in an array (not taking into for possible NaN values in this array).

This would be easy only working with double, but these FindMin and FindMax functions have to work with generics types.

I have tried to test for generic NaNs in this way:

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

but Equals is returning true for double.NaN ??!!

I have a workaround like this for now:

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);
}

My question is more about understanding why first solution did not work, is this a bug ?

You can find small test code here

Was it helpful?

Solution

but Equals is returning true for double.NaN

Yes. And it does regardless of generics:

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

Note that if the second line printed False, that would either make the IEquatable<T>.Equals inconsistent with the Equals(object) override, or you'd have to make Equals(object) violate the reflexivity requirement of object.Equals(object).

Basically this sort of thing is nasty whatever you do with it.

Given that you're trying to find max/min values, you might want to try using IComparable<T> instead of IEquatable<T> - that may well let you detect NaN in other ways. (I don't have time to check right now.)

OTHER TIPS

I would simply use double.IsNaN and let the compiler implicitly cast float members where required:

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));

"Wastes" a very small amount of memory on the stack and uses a cast op call, but hey ho it is generic enough to cater for any type that can hold a "numeric" NaN.

Alternatively, using float.IsNaN appears to work with rudimentary testing, but requires an explicit downcast of a double (downcasting double.NaN and 0.0 / 0.0 appears to work, as in, it reports NaN correctly).

You cannot generically constrain on a subset of value types with any cleanliness (or at all, I'm not 100% certain) so I wouldn't bother chasing the <T> route personally.


If you want a general solution that means the callee doesn't need to care what is passed in, you can do the following:

    static bool IsNaN(dynamic d)
    {
        float dub;

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

        return false;
    }

However, this incurs boxing. Note as well that dynamic is required and object will not work, so this also invokes the DLR (and also swallows all RuntimeBinderExceptions).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top