并行化的一种常见技术是融合嵌套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);
}
}
答案 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)
我想知道是否有更简单或更有效的方法吗?
是的,你必须开始的代码。请记住以下几点:
因此,对于世界上任何给定的CPU,您的第二个示例几乎可以保证比第一个示例慢得多。此外,它也完全不可读。