Обе части сокращения и коллапса в OMP смущают меня,
некоторые поднятые вопросы всплыли в моей голове
О развале ..
мы могли бы применить сжатие к вложенным циклам, но между ними должно быть несколько строк кода
например
for (int i = 0; i < 4; i++)
{
cout << "Hi"; //This is an extra line. which breaks the 2 loops.
for (int j = 0; j < 100; j++)
{
cout << "*";
}
}
1 & 2. За минус, что вы вычитаете из? Если у вас есть две темы, вы делаете result_thread_1 - result_thread_2
, или же result_thread_2 - result_thread_1
? Если у вас более двух потоков, это становится еще более запутанным: у меня только один отрицательный термин, а все остальные положительные? Есть только один положительный термин, а другие отрицательные? Это смесь? Какие результаты какие? Как такового нет, обходного пути нет.
В случае x++
или же x--
Предполагая, что они находятся в цикле сокращения, они должны происходить с каждым частичным результатом.
Да, я верю в это.
Условие сокращения требует, чтобы операция была ассоциативной и x = a[i] - x
операция в
for(int i=0; i<n; i++) x = a[i] - x;
не является ассоциативным Попробуйте несколько итераций.
n = 0: x = x0;
n = 1: x = a[0] - x0;
n = 2: x = a[1] - (a[0] - x0)
n = 3: x = a[2] - (a[1] - (a[0] - x0))
= a[2] - a[1] + a[0] - x0;
Но x = x - a[i]
работает, например
n = 3: x = x0 - (a[2] + a[1] + a[0]);
Однако есть обходной путь. Знак чередует каждый второй термин. Вот рабочее решение.
#include <stdio.h>
#include <omp.h>
int main(void) {
int n = 18;
float x0 = 3;
float a[n];
for(int i=0; i<n; i++) a[i] = i;
float x = x0;
for(int i=0; i<n; i++) x = a[i] - x; printf("%f\n", x);
int sign = n%2== 0 ? -1 : 1 ;
float s = -sign*x0;
#pragma omp parallel
{
float sp = 0;
int signp = 1;
#pragma omp for schedule(static)
for(int i=0; i<n; i++) sp += signp*a[i], signp *= -1;
#pragma omp for schedule(static) ordered
for(int i=0; i<omp_get_num_threads(); i++)
#pragma omp ordered
s += sign*sp, sign *= signp;
}
printf("%f\n", s);
}
Вот более простая версия, которая использует reduction
пункт. Следует отметить, что все нечетные термины — это один знак, а четные — другой. Таким образом, если мы делаем сокращение двумя членами за раз, знак не меняется, и операция является ассоциативной.
x = x0;
for(int i=0; i<n; i++) x = a[i] - x
можно уменьшить параллельно, как это.
x = n%2 ? a[0] - x0 : x0;
#pragma omp parallel for reduction (+:x)
for(int i=0; i<n/2; i++) x += a[2*i+1+n%2] - a[2*i+n%2];