OUTER LOOP(假定没有别名,允许别名请参见下文)
当您没有引用外部循环控制变量l 并且您甚至没有引用赋值的相同条款并且没有横向效果是在内循环中产生的,运行内循环是幂等的,运行一次或多次没有任何好处,所以一个非常好的优化是完全消除它@987654322 @,如下例所示:
pru.c
00001: #include <stdio.h>
00002: #include <stdlib.h>
00003: #define n 10
00004: #define loop 30
00005: void print(int x[], int y[], int z[])
00006: {
00007: int i;
00008: printf("%12s%12s%12s%12s\n","i", "x[]", "y[]", "z[]");
00009: for(i = 0; i < n; i++)
00010: printf("%12d%12d%12d%12d\n", i, x[i], y[i], z[i]);
00011: }
00012: int main()
00013: {
00014: int x[n], y[n], z[n];
00015: int i, l;
00016: for(i = 0; i < n; i++) {
00017: x[i] = rand();
00018: y[i] = rand();
00019: z[i] = rand();
00020: }
打印开头
00021: print(x, y, z);
接下来是发布的循环:
00022: for (l = 1; l <= loop; l++) {
00023: printf("iteration %d\n", l);
00024: for (i = 1; i<n; i++) {
00025: x[i] = z[i] * (y[i] - x[i - 1]);
00026: }
打印出来
00027: print(x, y, z);
00028: }
循环结束
00029: }
如您所见,循环传递之间的数组内容没有区别。接下来是运行程序来演示:
初始内容:
$ a.out
i x[] y[] z[]
0 33613 564950497 1097816498
1 1969887315 140734212 940422543
2 202055087 768218108 770072198
3 1866991770 1647128879 83392682
4 1421485336 148486083 229615973
5 127561358 735081006 33063457
6 1646757679 287085223 1793088605
7 802182690 382151770 1848710666
8 1486775472 115658218 394986197
9 661076908 1786703631 864107022
第一次迭代:
iteration 1
i x[] y[] z[]
0 33613 564950497 1097816498
1 -1607135687 140734212 940422543
2 1213242898 768218108 770072198
3 -1987622590 1647128879 83392682
4 -1113079323 148486083 229615973
5 -327431319 735081006 33063457
6 407021958 287085223 1793088605
7 1996444744 382151770 1848710666
8 500660170 115658218 394986197
9 -84727866 1786703631 864107022
iteration 2
i x[] y[] z[]
0 33613 564950497 1097816498
1 -1607135687 140734212 940422543
2 1213242898 768218108 770072198
3 -1987622590 1647128879 83392682
4 -1113079323 148486083 229615973
5 -327431319 735081006 33063457
6 407021958 287085223 1793088605
7 1996444744 382151770 1848710666
8 500660170 115658218 394986197
9 -84727866 1786703631 864107022
iteration 3
i x[] y[] z[]
0 33613 564950497 1097816498
1 -1607135687 140734212 940422543
2 1213242898 768218108 770072198
3 -1987622590 1647128879 83392682
4 -1113079323 148486083 229615973
5 -327431319 735081006 33063457
6 407021958 287085223 1793088605
7 1996444744 382151770 1848710666
8 500660170 115658218 394986197
9 -84727866 1786703631 864107022
... 重复迭代直到
iteration 30
i x[] y[] z[]
0 33613 564950497 1097816498
1 -1607135687 140734212 940422543
2 1213242898 768218108 770072198
3 -1987622590 1647128879 83392682
4 -1113079323 148486083 229615973
5 -327431319 735081006 33063457
6 407021958 287085223 1793088605
7 1996444744 382151770 1848710666
8 500660170 115658218 394986197
9 -84727866 1786703631 864107022
$ _
内循环
如果你重新排序内部表达式,你也可以在内部循环中获得一些好处,因为
x[0]
\----.
|
x[1] <+- y[1], z[1]
\---.
|
x[2] <+- y[2], z[2]
.
.
.
x[n-1]<+- y[n-1],z[n-1]
\--.
|
x[n] <+- y[n], z[n]
如果将表达式重新排列为x[i] = z[i]*y[i] - z[i]*x[i-1],则可以并行化所有z[i]*y[i]的计算,以及z[i]*x[i-1]的计算,只要x[i-1]的值被计算出来,在计算内循环。
thrd[0] thrd[1] thrd[2] ... thrd[j] ... thrd[n]
============================================================
z[1]*x[0] z[1]*y[1] z[2]*y[2] ... z[j]*y[j] ... z[n-1]*y[n-1]
| | | | |
\----------+-------. | | |
,---' | | | |
| | | | |
V V | | |
x[1] = z[1]*y[1] - z[1]*x[0] | | |
| | | |
`--------------------. | | |
| | | |
,-----------+-----' | |
| | | |
V V | |
x[2] = z[2]*y[2] - z[2]*x[1] | |
| | |
`--------------------. | |
,-----------+-------------------' |
| | |
... ... |
V V |
x[j] = z[j]*y[j] - z[j]*x[j-1] |
... |
| |
`---------------------------. |
| |
,-------------+------------------------------'
| |
V V
x[n-1] = z[n-1]*y[n-1]-z[n-1]*x[n-2]
这可以通过两个线程池有效地计算。以前你有n-1 产品和n-1 减法,现在你有2*n 产品和n-1 减法,并行计算,所以最终你从这种方法中没有节省(你得到两个线程工作,谢谢给向我显示错误的 KamiKaze)
考虑别名
从上图可以看出,内循环的计算只依赖x[0]、y[0...n-1]和z[0...n-1],而交叉值的唯一依赖由表达式x[1] = f(x[0],z[1],y[1])给出。如果您检查...如果我们将x 别名为z 或y,则表达式转换为x[j] = f(x[j-1],x[j], y[j]) 或x[j] = f(x[j-1],z[j],x[j]),这使得x[j] 的值通常取决于x[j] 的先前值。在这些情况下(x 别名为y 或z,或两者兼有)算法不是幂等的,并且无法消除外部循环。在仅将y 与z 混叠的情况下,表达式为x[j] = f(x[j-1], y[j])(或x[j] = f(x[j-1], z[j])),因此对先前的值不存在依赖性,并且算法是幂等的。
因此,总而言之,如果允许x 向量与y 或z 中的任何一个之间存在混叠,则无法消除外循环,并且必须保留。如果y 和z 出现别名,算法继续是幂等的,不需要外循环。