C#检查2D数组中任何元素是否为NaN或无穷大的最佳方法

C#检查2D数组中任何元素是否为NaN或无穷大的最佳方法,c#,multidimensional-array,C#,Multidimensional Array,有人知道检查2D数组中的元素是否为NaN或无穷大的最佳方法吗?我的数组可能很大,所以我不想在其中循环。我正在考虑使用 double[,] myArray; if ( !double.IsNaN(myArray.Cast<double>().Min() ) && !double.IsInfinity( myArray.Cast<double>().Min() ) { // have finite values as elements } doubl

有人知道检查2D数组中的元素是否为NaN或无穷大的最佳方法吗?我的数组可能很大,所以我不想在其中循环。我正在考虑使用

double[,] myArray;
if ( !double.IsNaN(myArray.Cast<double>().Min() ) && !double.IsInfinity( myArray.Cast<double>().Min() )
{
    // have finite values as elements
}
double[,]myArray;
如果(!double.IsNaN(myArray.Cast().Min())和&!double.IsInfinity(myArray.Cast().Min())
{
//将有限值作为元素
}
对于NaN和无穷大检查。我只需要知道数组中是否有NaN或无穷大的元素,因此我认为只检查数组中最小的元素就可以解决NaN和无穷大的问题。有更好的方法吗?感谢您提供的任何帮助或建议。

手动编码的loop比建议的Linq替代方案快得多。请参阅下面的更新2

由于没有为数组指定顺序,因此您将以某种方式循环遍历数组的每个元素来回答您的问题

您的代码正是这样做的,隐藏了循环的实现。使用Linq is进行循环至少比为循环编写自己的
要慢一些,因为它会做更多的工作。(事实上,由于没有缓存
myArray.Cast().Min()
)的结果,所以您在数组中循环了两次)

对于大多数处理器,当循环遍历相邻的内存地址时,应该遍历循环(在我自己的测试中,以错误的顺序遍历可能会慢30%)

如果数组中的值实际上存在某种顺序,则可能会进行更有效的搜索

更新

我怀疑手工编码的循环会比使用Linq快得多,因为循环体很简单。如果最后一点性能都很重要,我建议您同时实现选项和基准测试

里德关于并行运行的建议也值得进行基准测试。您可以非常轻松地使用

更新2

测量了里德溶液和手动编码回路的性能

Linq:1448.6353毫秒

对于回路:125.2208 ms

使用的代码:

class Program
{
    const int SIZE = 3000;
    static double[,] data = new double[SIZE,SIZE];


    static void Main(string[] args)
    {
        if (args.Length >= 1 && args[0] == "/for")
        {
            Benchmark(ForLoop);
        }
        else
        {
            Benchmark(LinqLoop);
        }
    }

    static void ForLoop()
    {
        for (int i = 0; i < SIZE; i++)
        {
            for (int j = 0; j < SIZE; j++)
            {
                if (double.IsNaN(data[i, j]) || double.IsInfinity(data[i, j])) Console.WriteLine("FOUND!");
            }
        }
    }

    static void LinqLoop()
    {
        if (!data.Cast<double>().Any(d => double.IsNaN(d) || double.IsInfinity(d))) Console.WriteLine("FOUND!");
    }

    static void Benchmark(Action a)
    {
        Stopwatch watch = Stopwatch.StartNew();
        a();

        TimeSpan span = watch.Elapsed;
        Console.WriteLine("Milliseconds: " + span.TotalMilliseconds + " ms");
        Console.ReadKey();
    }
}
类程序
{
常数int SIZE=3000;
静态双精度[,]数据=新双精度[尺寸,尺寸];
静态void Main(字符串[]参数)
{
如果(args.Length>=1&&args[0]=“/for”)
{
基准(ForLoop);
}
其他的
{
基准测试(LinqLoop);
}
}
静态void ForLoop()
{
对于(int i=0;idouble.IsNaN(d)| | double.IsInfinity(d)))Console.WriteLine(“FOUND!”);
}
静态无效基准(动作a)
{
秒表=Stopwatch.StartNew();
a();
TimeSpan=watch.passed;
Console.WriteLine(“毫秒:+span.total毫秒+“毫秒”);
Console.ReadKey();
}
}

我个人会使用:

if (!myArray.Cast<double>().Any(d => double.IsNaN(d) || double.IsInfinity(d)))
{
     // All have correct values...

对于非常大的阵列,这通常比直接循环更有效,因为多个核可以通过PLINQ处理分区数据。

您建议的解决方案在阵列上执行两次传递。您可以这样做(Linqy):

static bool HasBadData(双[,]双)
{
bool hasBadData=doubles.Cast()
.Any(x=>double.isnfinity(x)| | double.IsNaN(x))
;
返回数据;
}
或者更直接、非Linq的方式:

static bool HasBadData( double[,] doubles )
{
  bool hasBadData = false ;
  for ( int i = 0 ; !hasBadData && i < doubles.GetLength(0) ; ++i )
  {
    for ( int j = 0 ; !hasBadData && j < doubles.GetLength( 1 ) ; ++j )
    {
      double d = doubles[i,j] ;
      hasBadData = double.IsInfinity(d) || double.IsNaN(d) ;
    }
  }
  return hasBadData ;
}
static bool HasBadData(双[,]双)
{
bool hasBadData=false;
对于(int i=0;!hasBadData&&i
虽然我怀疑非Linq方法的性能会稍微好一点,但事实上,它是一个半打中的六个

“我的阵列可能很大,因此我不希望在其中循环。”

通过它进行循环是访问所有元素的唯一方法。以这种或那种方式需要循环

如果您担心性能,则不应使用LINQ,因为它会产生迭代器和委托调用开销。请使用
safe
code将该数组视为1D数组来遍历该数组的所有元素

JIT无法优化多维数组的边界检查

像这样:

fixed (double* arrayPtr = array) {
 var count = width * height;
 for (int i = 0; i < count; i++) {
  if (double.IsNaN(arrayPtr[i]) || double.IsInfinity(arrayPtr[i]))
   return true;
 }
}
return false;
fixed(双*arrayPtr=array){
变量计数=宽度*高度;
for(int i=0;i

可能比LINQ解决方案快10倍。LINQ非常重于间接寻址,这对现代CPU的性能是有害的。基于直线循环的代码通常要快得多。

感谢您的响应。我理解循环。我的意思是说编写一组显式嵌套for循环。我的代码会起作用吗?它会吗还有正无穷大?还有,有更好的方法吗?@PBrenek我不相信它能抓住正无穷大,就像你写的那样…它的效率也远远低于它所能达到的水平。@Eric J谢谢。我意识到发布的代码中存在双循环。我不知道如何先按行大顺序迭代。最后,没有priori数组中值的顺序。我正在寻找进行此检查的最快方法。@Eric J我不知道Parallel.For。我想我需要对这两种方法进行基准测试。谢谢。@EricJ-您的代码不一样-您在LINQ中使用if
(!data.Cast
),但在循环中使用if(true
)(不是impa
static bool HasBadData( double[,] doubles )
{
  bool hasBadData = false ;
  for ( int i = 0 ; !hasBadData && i < doubles.GetLength(0) ; ++i )
  {
    for ( int j = 0 ; !hasBadData && j < doubles.GetLength( 1 ) ; ++j )
    {
      double d = doubles[i,j] ;
      hasBadData = double.IsInfinity(d) || double.IsNaN(d) ;
    }
  }
  return hasBadData ;
}
fixed (double* arrayPtr = array) {
 var count = width * height;
 for (int i = 0; i < count; i++) {
  if (double.IsNaN(arrayPtr[i]) || double.IsInfinity(arrayPtr[i]))
   return true;
 }
}
return false;