【问题标题】:Loop Unrolling Multi Dimesional Array循环展开多维数组
【发布时间】:2013-11-16 00:39:55
【问题描述】:

我最近尝试在这个多维数组中展开内部 i 和 j 循环,但是 filter->get(i,j) 总是弄乱图像的纹理。谁能帮助我展开 i 和 j 循环?谢谢。

我的尝试:

double
applyFilter(struct Filter *filter, cs1300bmp *input, cs1300bmp *output)
{

     long long cycStart, cycStop;

     cycStart = rdtscll();

    output -> width = input -> width;
    output -> height = input -> height;
int a = filter -> getDivisor();
int n = filter -> getSize();
for (int plane = 0; plane < 3; plane++){
    for(int row = 1; row < (input -> height) - 1 ; row = row + 1) {
        for(int col = 1; col < (input -> width) - 1; col = col + 1) {
            int value = 0;
            int val1, val2;
            for (int j = 0; j < n; j++) {
                for (int i = 0; i < n; i+=2) {
                    val1 = val1 + input -> color[plane][row + i - 1][col + j - 1]
                    * filter -> get(i, j);
                    val2 = val2 + input -> color[plane][row + i][col + j -1] * filter->get(i+1,j);
                }
            }
            value = (val1 + val2) / a;
            if ( value  < 0 ) { value = 0; }
            if ( value  > 255 ) { value = 255; }
            output -> color[plane][row][col] = value;
        }

    }
}

 cycStop = rdtscll();
 double diff = cycStop - cycStart;
 double diffPerPixel = diff / (output -> width * output -> height);
 fprintf(stderr, "Took %f cycles to process, or %f cycles per pixel\n",
  diff, diff / (output -> width * output -> height));

 return diffPerPixel;
}

原文:

int a = filter -> getDivisor();
int n = filter -> getSize();    
for (int plane = 0; plane < 3; plane++){
    for(int row = 1; row < (input -> height) - 1 ; row = row + 1) {
        for(int col = 1; col < (input -> width) - 1; col = col + 1) {
            int value = 0;
            for (int j = 0; j < n; j++) {
                for (int i = 0; i < n; i++) {
                    value = value + input -> color[plane][row + i - 1][col + j - 1]
                    * filter -> get(i, j);
                }
            }
            value = value / a;
            if ( value  < 0 ) { value = 0; }
            if ( value  > 255 ) { value = 255; }
            output -> color[plane][row][col] = value;

【问题讨论】:

    标签: c performance optimization loop-unrolling


    【解决方案1】:

    尝试将内部循环替换为:

    int value = 0;
    int val1 = 0, val2 = 0;
    for (int j = 0; j < n; j++) { 
        int i;
        for (i = 0; i < n; i+=2) {
            val1 += input->color[plane][row+i-1][col+j-1] * filter->get(i,j);
            val2 += input->color[plane][row+i  ][col+j-1] * filter->get(i+1,j);
        } 
        if (i < n)
            val1 += input->color[plane][row+i-1][col+j-1] * filter->get(i,j);
    } 
    value = (val1 + val2) / a;
    

    【讨论】:

      【解决方案2】:

      只有当 n 是 2 的倍数时,你的方法才是正确的。否则你会漏掉一行。

      添加:

      首先,我刚刚意识到您忘记初始化val1val2,这可能是您出现问题的主要原因。

      其次,在我看来,您的代码是专门为过滤器大小为 3 编写的:

      • 对于较小的过滤器,您根本无法访问边界。
      • 对于较大的,您可以访问图片之外的位置,例如 [row + i - 1] 变得大于或等于 input-&gt;height

      如果您只想使用大小为 3 的过滤器,那么我会简单地完全展开内部循环。否则检查行和列值的边界。

      现在,对于循环展开,我建议您进行 google 搜索,因为您可以找到许多有关如何正确执行此操作的示例。一个可以在wikipedia page 上找到。

      在您的情况下,最简单的解决方案是:

      int value = 0;
      int val1=0, val2=0;
      for (int j = 0; j < n; j++) {
          for (int i = 0; i < n-1; i+=2) {
              val1 = val1 + input->color[plane][row+i-1][col+j-1] * filter->get(i  ,j);
              val2 = val2 + input->color[plane][row+i  ][col+j-1] * filter->get(i+1,j);
          }
          if (n%2 !=0) {
              val1 = val1 + input->color[plane][row+n-2][col+j-1] * filter->get(n-1,j);
          }
      }
      value = (val1 + val2) / a;
      

      如果您想进一步展开循环,更通用的方法是(例如 4):

      int value = 0;
      int val1=0, val2=0, val3=0, val4=0;
      for (int j = 0; j < n; j++) {
      
          for (int i = 0; i < n-3; i+=4) {
              val1 = val1 + input->color[plane][row+i-1][col+j-1] * filter->get(i  ,j);
              val2 = val2 + input->color[plane][row+i  ][col+j-1] * filter->get(i+1,j);
              val3 = val3 + input->color[plane][row+i+1][col+j-1] * filter->get(i+2,j);
              val4 = val4 + input->color[plane][row+i+2][col+j-1] * filter->get(i+3,j);
          }
          switch (n % 4) {
              case 3: val1+=input->color[plane][row+n-4][col+j-1] * filter->get(i+n-3,j);
              case 2: val1+=input->color[plane][row+n-3][col+j-1] * filter->get(i+n-2,j);
              case 1: val1+=input->color[plane][row+n-2][col+j-1] * filter->get(i+n-1,j);
          }
          value = (val1 + val2 + val3 + val4) / a;
      }
      

      注意:
      请注意,根据过滤器的大小、使用的编译器和编译器选项以及您的系统,上述解决方案可能不会加快您的代码速度,甚至会减慢它的速度。您还应该知道,如果有意义,编译器通常可以为您执行循环展开(例如,使用 gcc 中的 -funroll-loops 选项)。

      【讨论】:

      • 所以我可以这样做:for (;i color[plane][row+i-1][col+j-1] * filter->get(i,j)} 基本上弥补了其余部分。
      • 我修改了我的答案,以便为您的问题提供更完整的答案。我希望我没有对索引犯任何错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-30
      • 2013-06-25
      • 2015-06-02
      • 2019-07-17
      • 2012-05-13
      • 1970-01-01
      相关资源
      最近更新 更多