我需要在数组中找到最小值和最大值(不考虑此数组中可能的NaN值).
这很容易使用double,但是这些FindMin和FindMax函数必须使用泛型类型.
我试图用这种方式测试通用 NaN:
bool isNaN<T>(T value) where T : IEquatable<T>
{
return !value.Equals(value);
}
Run Code Online (Sandbox Code Playgroud)
但是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);
}
Run Code Online (Sandbox Code Playgroud)
我的问题更多的是理解为什么第一个解决方案不起作用,这是一个错误吗?
你可以在这里找到小的测试代码
我只是使用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));
Run Code Online (Sandbox Code Playgroud)
"浪费"是堆栈中非常少量的内存,并使用强制转换操作,但是它很通用,足以满足任何可以容纳"数字"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;
}
Run Code Online (Sandbox Code Playgroud)
然而,这导致拳击.注意这dynamic是必需的并且object不起作用,因此这也调用DLR(并且还吞下所有RuntimeBinderExceptions).
但是Equals正在为double.NaN返回true
是.它不管泛型如何:
double x = double.NaN;
Console.WriteLine(x.Equals(x)); // True
Console.WriteLine(x == x); // False
Run Code Online (Sandbox Code Playgroud)
请注意,如果第二行打印为False,则会导致IEquatable<T>.Equals与Equals(object)覆盖不一致,或者您必须Equals(object)违反反射性要求object.Equals(object).
无论你用它做什么,基本上这种事都很讨厌.
鉴于您正在尝试查找最大值/最小值,您可能希望尝试使用IComparable<T>而不是IEquatable<T>- 这可能会让您以其他方式检测NaN.(我现在没时间检查.)