Давайте просто рассмотрим случай с нитями = 1.Это:
#pragma omp parallel for private(i, j, tid) reduction(+:suma)
for(i = 0; i < steps; i++){
for(j = (steps / nthreads) * tid; j < (steps / nthreads) * (tid + 1); j += dx){
suma += ((j * j * j) + ((j + dx) * (j + dx) * (j + dx))) / 2 * dx;
}
}
превращается в это:
for(i = 0; i < steps; i++){
for(j = 0; j < steps; j += dx){
suma += ((j * j * j) + ((j + dx) * (j + dx) * (j + dx))) / 2 * dx;
}
}
, и вы можете начать видеть проблему;вы в основном зацикливаетесь на шаги 2 .
Кроме того, ваш второй цикл не имеет никакого смысла, так как вы увеличиваете на dx.Та же самая путаница между признаками (i, j) и местоположениями в физической области (i * dx) проявляется в вашем приращении.j+dx
не имеет никакого смысла.Предположительно, вы хотите увеличить suma
на (f (x) + f (x ')) * dx / 2 (например, правило трапеции);это должно быть
float x = down + i*dx;
suma += dx * ((3 * x * x + 1) + (3 * (x + dx) * (x + dx) + 1)) / 2;
Как указывает эбо, вы хотите суммировать integrand , а не его антидериватив.
Теперь, если мы включим проверку ответа:
printf("For %d steps the area of the integral 3 * x^2 + 1 from %f to %f is: %f (expected: %f)\n",
steps, down, up, suma, up*up*up-down*down*down + up - down);
и мы запускаем его последовательно, мы начинаем получать правильный ответ:
$ ./foo 10
For 10 steps the area of the integral 3 * x^2 + 1 from 1.000000 to 100.000000 is: 1004949.375000 (expected: 1000098.000000)
Runtime: 0
$ ./foo 100
For 100 steps the area of the integral 3 * x^2 + 1 from 1.000000 to 100.000000 is: 1000146.562500 (expected: 1000098.000000)
Runtime: 0
$ ./foo 1000
For 1000 steps the area of the integral 3 * x^2 + 1 from 1.000000 to 100.000000 is: 1000098.437500 (expected: 1000098.000000)
Runtime: 0
Нет никакого смысла беспокоиться о случае OpenMP, пока не сработает случай с последовательным интерфейсом.
Как только ebo указывает на OpenMP, самое простое, что нужно сделать, это просто позволить OpenMP выполнить декомпозицию вашего цикла: например,
#pragma omp parallel for reduction(+:suma)
for(i = 0; i < steps; i++){
float x = down + i*dx;
suma += dx * ((3 * x * x + 1) + (3 * (x + dx) * (x + dx) + 1)) / 2;
}
Запуск этого,каждый получает
$ setenv OMP_NUM_THREADS 1
$ ./foo 1000
For 1000 steps the area of the integral 3 * x^2 + 1 from 1.000000 to 100.000000 is: 1000098.437500 (expected: 1000098.000000)
Runtime: 0
$ setenv OMP_NUM_THREADS 2
$ ./foo 1000
For 1000 steps the area of the integral 3 * x^2 + 1 from 1.000000 to 100.000000 is: 1000098.437500 (expected: 1000098.000000)
Runtime: 0
$ setenv OMP_NUM_THREADS 4
$ ./foo 1000
For 1000 steps the area of the integral 3 * x^2 + 1 from 1.000000 to 100.000000 is: 1000098.625000 (expected: 1000098.000000)
Runtime: 0
$ setenv OMP_NUM_THREADS 8
$ ./foo 1000
For 1000 steps the area of the integral 3 * x^2 + 1 from 1.000000 to 100.000000 is: 1000098.500000 (expected: 1000098.000000)
Можно явно блокировать в OpenMP, если вы действительно этого хотите, но у вас должна быть причина для этого.