融合三角形循环进行并行化,计算子索引

时间:2014-06-03 11:18:29

标签: c++ c math for-loop

并行化的一种常见技术是融合嵌套for循环

for(int i=0; i<n; i++) {
    for(int j=0; j<n; j++) {

for(int x=0; x<n*n; x++) {
    int i = x/n; int j = x%n;

我想知道我怎么能这样做来融合像这样的三角形循环

for(int i=0; i<n; i++) {
   for(int j=0; j<i+1; j++) {

这有n*(n+1)/2次迭代。让我们调用融合迭代x。使用二次方程式我得出了这个:

for(int x=0; x<(n*(n+1)/2); x++) {      
    int i  = (-1 + sqrt(1.0+8.0*x))/2;
    int j = x - i*(i+1)/2;

与融合方形循环不同,这需要使用sqrt函数以及从int到float以及从float到int的转换。

我想知道是否有更简单或更有效的方法吗?例如,一个解决方案,它不需要sqrt函数或转换从int到float或float到int。

编辑:我不想要一个依赖于上一次或下一次迭代的解决方案。我只想要像int i = funci(x) and int j = funcj(x,i)这样的解决方案

以下代码显示了这一点:

#include <stdio.h>
#include <math.h>
int main() {
    int n = 5;
    int cnt = 0;
    for(int i=0; i<n; i++) {
        for(int j=0; j<i+1; j++) {
            printf("%d: %d %d\n", cnt++, i,j);      
        }
    } printf("\n");

    int nmax = n*(n+1)/2;
    for(int x=0; x<nmax; x++) {     
        int i  = (-1 + sqrt(1.0+8.0*x))/2;
        int j = x - i*(i+1)/2;
        printf("%d: %d %d\n", x,i,j);
    }       
}

3 个答案:

答案 0 :(得分:6)

考虑到您尝试将三角形融合为并行化的目的,非显而易见的解决方案是选择x到(i,j)的非平凡映射:

j |\ i ->
  | \             ____
| |  \    =>    |\\   |
V |___\         |_\\__|

毕竟,您没有按照任何特殊顺序处理它们,因此确切的映射是无所谓。

因此,您要为矩形计算x->i,j,但如果i > j{ i=N-i, j = N-j }(镜像Y轴,则镜像X轴)。

   ____
 |\\   |      |\           |\
 |_\\__|  ==> |_\  __  =>  | \
                  / |      |  \
                 /__|      |___\

答案 1 :(得分:1)

最理智的形式当然是第一种形式。

也就是说,融合形式最好用条件完成:

int i = 0; int j = 0;
for(int x=0; x<(n*(n+1)/2); x++) {
  // ...
  ++j;
  if (j>i)
  {
    j = 0;
    ++i;
  }
}

答案 2 :(得分:0)

  

我想知道是否有更简单或更有效的方法吗?

是的,你必须开始的代码。请记住以下几点:

  • 浮点运算不存在比普通整数快的情况。
  • 但是有很多情况下浮点比普通整数慢得多。 FPU或没有FPU。
  • 在大多数系统中,浮点变量通常大于普通整数,因此仅因此而变慢。
  • 代码的第一个版本可能对缓存内存最友好。对于任何手动优化的情况,这完全取决于您使用的CPU。
  • 无论是对普通整数还是浮点数,大多数系统的分区通常都很慢。
  • 任何形式的复杂算术都会比简单计算慢。

因此,对于世界上任何给定的CPU,您的第二个示例几乎可以保证比第一个示例慢得多。此外,它也完全不可读。