Код:
double x(){return (double)rand()/(double)RAND_MAX;}
double y(){return (double)rand()/(double)RAND_MAX;}
double z(){return (double)rand()/(double)RAND_MAX;}
int d(double x, double y, double z){
if ( ( (pow(x,2)+pow(y,2)) <1 ) && ( z<=1 && z>=0 )) return 1;
return 0;
}
double f(double x, double y, double z){
return 1;
}
#pragma omp parallel default(none) private(id,numt,j,local_sum,local_good_dots,local_coi,x_,y_,z_) shared(total_sum,good_dots,count_of_iterations)
{
local_coi = count_of_iterations;
id = omp_get_thread_num() + 1;
numt = omp_get_num_threads();
#pragma omp for
for (j = 1; j <= local_coi; j++){
x_=x();
y_=y();
z_=z();
if (d(x_,y_,z_) == 1){
local_sum += f(x_,y_,z_);
local_good_dots += 1;
}
}
#pragma omp critical
{
total_sum = total_sum + local_sum;
good_dots = good_dots + local_good_dots;
}
}
Комментарий: Этот код является реализацией метода Монте-Карло для вычисления трехмерного интеграла функции f()
в области d()
.
Я ожидаю, что этот код будет работать быстрее в многопоточном режиме (openmp).
Но что-то пошло не так.
После нескольких часов модификаций (reduction
в прагме openmp, упрощения if-условия (типа f(x_,y_,z_) * d(x_,y_,z_)
)) я так и не понял, почему этот простой цикл становится медленнее при большем количестве потоков.
Но после того, как я создаю трехмерный массив для каждой координаты перед циклом и добавляю его в shared
, моя программа становится быстрее.
Итак, вопрос:
Как изменить этот код и какие функции (операции) разрешены в параллельных блоках?
P.S: как я вижу, эта функция rand
не разрешена (или я ошибаюсь?)
Спасибо за помощь!
Модификация (с помощью @HristoIliev)
double x(){return (double)rand()/(double)RAND_MAX;}
double y(){return (double)rand()/(double)RAND_MAX;}
double z(){return (double)rand()/(double)RAND_MAX;}
int d(double x, double y, double z){
if ( ( (pow(x,2)+pow(y,2)) <1 ) && ( z<=1 && z>=0 )) return 1;
return 0;
}
double f(double x, double y, double z){
return 1;
}
#pragma omp parallel default(none) private(j,local_coi,x_,y_,z_) shared(count_of_iterations) reduction(+:total_sum,good_dots)
{
local_coi = count_of_iterations;
#pragma omp for(prng)
for (j = 1; j <= local_coi; j++){
#pragma omp critical(prng)
{
x_=x();
y_=y();
z_=z();
}
if (d(x_,y_,z_) == 1){
total_sum += f(x_,y_,z_);
good_dots += 1;
}
}
}