2012-08-24 65 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