【问题标题】:unswitch while loop optimization in c在c中取消切换while循环优化
【发布时间】:2016-06-29 21:25:16
【问题描述】:

我很难通过 Loop Unswitching 来优化以下 while 循环。我已经尝试应用来自wiki 的示例,但是我很难将它应用到while 循环中。我有以下代码:

int n = 5,
    m = 5,
    i = 0,
    val = 0;

while (i < n ) {
  j = 0;

  while (j < m ) {
    if (i < j ) {
      val = val + i ;
    }
    else if ( j == i ) {
      val = val - 1;
    }
    else {
      val = val + j ;
    }

    j = j + 1;
  }

  i = i + 1;
}

并尝试通过以下方式取消切换:

while (i < n ) {
  j = 0;

  if (i < j ) {
    while (j < m ) {
      val = val + i;
      j = j + 1;
    }
  }

  if ( j == i ) {
    while (j < m) {
      val = val - 1;
      j = j + 1;
    }
  }

  if (i > j) {
    while (j < m) {
      val = val + j;
      j = j + 1;
    }
  }

  i = i + 1;
}

我可能做错了什么。

【问题讨论】:

  • 您忘记提及您要达到的目标。这是XY Problem?
  • 打印val 给出15。所以你想要∑nn = 1..5?有更简单的方法来计算这一点。但我们不知道您要计算什么。
  • 嗯,我有这个问题作为作业。只是试图为非切换循环和非切换循环获得相同的结果,并考虑到网上没有关于 while 循环的相关示例,我在这里尝试过。
  • UvA 的 Compilerbouw 有机会吗? ——

标签: c loops optimization compiler-optimization


【解决方案1】:

最好在铅笔和纸的帮助下展开此类循环。您想要以下网格的总和:

           0   1   2   3   4  |   5   n

    0     -1   0   0   0   0  |   0   0
    1      0  -1   1   1   1  |   1   1
    2      0   1  -1   2   2  |   2   2
    3      0   1   2  -1   3  |   3   3
    m      0   1   2   3  -1  |   4   4

网格可以细分为三部分:对角线、正方形部分中对角线旁边的上下三角形以及nm不同时的矩形块。

让我们用正方形部分和矩形部分k·r来表示网格的尺寸:

    k = min(n, m)
    r = max(m, n) - k

现在您可以看到这三个部分贡献了哪些总和:

    val = 2·∑(k - i - 1)·i       # two triangles
        + r·∑(i)                 # rectangle
        - k                      # diagonal

(所有总和都来自i = 0; i &lt; n; i++。)这个总和可以重新排列为:

    val = 2·(k - 1)·∑(i) - 2*∑(i²) + r·(i) - k
        = (2·k + r - 2)·∑(i) - 2*∑(i²) - k

这减少了您的两个嵌套循环两个两个独立的循环来计算自然数及其平方的总和。幸运的是,这些总和可以用简单的关系表示:

    ∑(i) = (n - 1)·n / 2
   ∑(i²) = (2·n - 1)·(n - 1)·n / 6

您现在有了一个用于计算结果总和的恒定时间公式:

    int val(int n, int m)
    {
        int k = (n < m) ? n : m;
        int r = ((n > m) ? n : m) - k;

        return (2*k + r - 2) * (k - 1) * k / 2
              - (2*k - 1) * k * (k - 1) / 3 - k;
    }

当然,所有这些都与循环展开无关。

【讨论】:

    【解决方案2】:

    Loop unswitching according to wikipedia 是一个编译器优化,所以我有点困惑为什么你需要自己做这件事,但我认为这在分解 for..ifs 方面已经很好了

    for (i = 0; i < n; ++i) {
      // j < i
      for (j = 0; j < i; ++j) {
        val = val + j;
      }
    
      // j == i
      val = val - 1;
    
      // j > i
      for (j = i + 1; j < m; ++j) {
        val = val + i;
      }
    }
    

    这不是一个传统上可以取消切换的循环,因为这里的条件变量是循环变量。

    【讨论】:

    • 我还冒昧地将您的 while 循环更改为 for 循环。我推荐这种做法; for 循环更容易推理。
    • 这当然可能是有人试图学习/构建编译器,因此手动进行优化(根据练习)然后实现它。
    猜你喜欢
    • 2020-03-25
    • 2014-12-28
    • 2020-06-24
    • 2018-03-01
    • 2020-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多