我需要在数组中找到min和max值(不考虑可能的NaN值在这个数组中)。
这只使用 double
会很容易,但是这些 FindMin 和 FindMax 函数必须使用泛型类型。
我尝试以这种方式测试通用 NaN:
bool isNaN<T>(T value) where T : IEquatable<T>
{
return !value.Equals(value);
}
但是 Equals
为 double.NaN
返回 true
??!!
我现在有这样的解决方法:
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
最佳答案
我会简单地使用 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
s)。
关于c# - 如何使用泛型测试 NaN(或者为什么 NaN.Equals(NaN) == true)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12109345/