我需要在数组中找到 min 和 max 值(不考虑可能的 NaN 值在这个数组中)。
这只适用于double
,但这些FindMin和FindMax函数必须使用泛型类型。
我试图以这种方式测试通用 NaN:
bool isNaN<T>(T value) where T : IEquatable<T>
{
return !value.Equals(value);
}
但是Equals
正在为true
?? !!
double.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
答案 0 :(得分: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.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(并且还会吞下所有RuntimeBinderException
)。
答案 1 :(得分:5)
但是对于double.NaN
,Equals返回true
是。它无论泛型如何都是如此:
double x = double.NaN;
Console.WriteLine(x.Equals(x)); // True
Console.WriteLine(x == x); // False
请注意,如果第二行打印为False,则会导致IEquatable<T>.Equals
与Equals(object)
覆盖,或不一致,您必须{{1}违反了Equals(object)
的反身性要求。
基本上,无论你用它做什么,这种事都很讨厌。
鉴于您正在尝试查找最大/最小值,您可能希望尝试使用object.Equals(object)
而不是IComparable<T>
- 这可能会让您以其他方式检测到NaN。 (我现在没时间检查。)