融合一个三角形循环并行化,计算子指标

Fusing a triangle loop for parallelization, calculating sub-indices

本文关键字:计算 并行化 合一 三角形 循环 融合      更新时间:2023-10-16

一个常见的并行化技术是像这样融合嵌套的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 %dn", 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 %dn", x,i,j);
    }       
}

考虑到您正在尝试将三角形与并行化的意图融合在一起,不明显的解决方案是选择x到(i,j)的非平凡映射:

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

毕竟,你没有按照任何特殊的顺序处理它们,所以确切的映射是一个不关心的。

所以计算x->i,j就像你对矩形做的那样,但如果i > j那么{ i=N-i, j = N-j }(镜像Y轴,然后镜像X轴)。

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

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

也就是说,融合形式更适合使用条件句:

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

我想知道是否有更简单或更有效的方法来做到这一点?

是的,你必须开始的代码。请注意以下事项:

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

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