2012-08-24 66 views
3

我需要找到分钟最大值在阵列值(未考虑到了可能的NaN值这个阵列中)。如何使用泛型测试NaN(或为什么NaN.Equals(NaN)== true)?

这将很容易只使用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); 
} 

我的问题更多的是理解为什么第一个解决方案没有工作,这是一个错误?

你可以找到小测试代码here

+1

该代码是否应该读取'value.Equals(value)'?或者更像'value.Equals(...其他值...)'? –

+0

var result = double.NaN.Equals(double.NaN); //结果是真的。 –

+0

为什么你会期望测试一个值等于自己是假的? –

回答

5

但Equals已为double.NaN

是返回true。不管它确实仿制药:

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

注意,如果第二行打印假的,要么使IEquatable<T>.Equals不符合Equals(object)覆盖,你就必须做出Equals(object)违反的反身性要求object.Equals(object)

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

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

+0

+1解决主要问题。 –

+0

谢谢理解NaN.Equals(NaN)真正意义的含义。我已经尝试过IComparable,但没有定论。无论如何,你的答案完全符合我的需求和奇迹,谢谢:) – CitizenInsane

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的类型。

另外,使用float.IsNaN出现与初步测试工作,但需要double的明确垂头丧气(向下转换double.NaN0.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(并且吞下所有RuntimeBinderException)。

+0

即使沉重,当然,我没有想过动态。好的方法。谢谢 :) – CitizenInsane