有限差分法中的性能问题

时间:2016-05-29 05:37:44

标签: c performance loops multidimensional-array

我写了一段C代码,它使用有限差分法估算值。这是一种平均方法。我分析了代码,发现一个iterate()函数是最慢的。

void iterate(double data[][ARRAY_SIZE], int nx, int ny, int dx, int dy)
{
    for (int i = 0; i < nx; ++i)
    {
        for (int j = 0; j < ny; ++j)
        {
            if (i % (dx + 1) == 0 && j % (dy + 1) == 0)
                continue;
            else if (i == 0 && 0 < j && j < ny)
                data[i][j] = (data[i][j - 1] + data[i][j + 1] + data[i + 1][j]) / 3;
            else if (j == 0 && 0 < i && i < nx)
                data[i][j] = (data[i - 1][j] + data[i + 1][j] + data[i][j + 1]) / 3;
            else if (i == nx - 1 && 0 < j && j < ny)
                data[i][j] = (data[i][j - 1] + data[i][j + 1] + data[i - 1][j]) / 3;
            else if (j == ny - 1 && 0 < i && i < nx)
                data[i][j] = (data[i - 1][j] + data[i + 1][j] + data[i][j - 1]) / 3;
            else
                data[i][j] = (data[i - 1][j] + data[i + 1][j] + data[i][j - 1] + data[i][j + 1]) / 4;
        }
    }
}

这个循环运行缓慢,我不知道我在这里缺少什么使它变慢。还有更好的方法吗?

使用400x400 double数组的2000次迭代需要

real    0m1.950s
user    0m1.940s
sys 0m0.004s

2 个答案:

答案 0 :(得分:3)

以下是一些想法:

  1. ny似乎必须等于ARRAY_SIZE。您也可以省略它作为参数,只使用编译时常量。
  2. 除最后一个之外的所有if / else子句仅适用于特定的行或列。所以提升他们。例如,您可以在执行边缘外的整个矩阵之前将第一行和第一行作为1D循环处理,然后最后处理最右边的列和底行。
  3. 最后,你的核心循环应该更像这样:

    for (int i = 1; i < nx - 1; ++i)
    {
        for (int j = 1; j < ARRAY_SIZE - 1; ++j)
        {
            data[i][j] = (data[i - 1][j] + data[i + 1][j] + data[i][j - 1] + data[i][j + 1]) / 4;
        }
    }
    

答案 1 :(得分:1)

考虑这个实现:

void iterate(double data[][ARRAY_SIZE], int nx, int ny, int dx, int dy)
{
    // because nx - 1 and ny - 1 are used
    nx--;
    ny--;
    // because dx + 1 and dy + 1 are used
    dx++;
    dy++;

    int i = 0;
    int j = 0;

    // case i == 0 && 0 < j && j < ny
    for (j = 1; j < ny; ++j)
    {
        if (j % dy)
            data[0][j] = (data[i][j - 1] + data[i][j + 1] + data[i + 1][j]) / 3.0;
    }

    j = 0;

    // case j == 0 && 0 < i && i < nx
    for (i = 1; i < nx; ++i)
    {
        if (i % dx)
            data[i][0] = (data[i - 1][j] + data[i + 1][j] + data[i][j + 1]) / 3.0;
    }

    // default case
    for (i = 1; i < nx; ++i)
    {
        for (j = 1; j < ny; ++j)
        {
            if (i % dx || j % dy)
                data[i][j] = (data[i - 1][j] + data[i + 1][j] + data[i][j - 1] + data[i][j + 1]) * 0.25;
        }
    }

    // case i == nx && 0 < j && j < ny
    for (j = 1; j < ny; ++j)
    {
        if (nx % dx || j % dy)
            data[nx][j] = (data[i][j - 1] + data[i][j + 1] + data[i - 1][j]) / 3.0;
    }

    // case j == ny && 0 < i && i < nx
    for (i = 1; i < nx; ++i)
    {
        if (ny % dy || i % dx)
            data[i][ny] = (data[i - 1][j] + data[i + 1][j] + data[i][j - 1]) / 3.0;
    }
}

主要的三点是:

  1. 减少双循环
  2. 的内循环中的操作量
  3. 通过仅执行一次
  4. 来减少琐碎操作的数量
  5. 不要混合数据类型并强制强制(使用/ 3.0* 0.25
  6. 我的代码中唯一没有解释的是i % dx || j % dy等于!(i % dx == 0 && j % dy == 0)