OpenMP并行用于模运算

时间:2014-04-30 06:46:17

标签: openmp

我正在学习OpenMP并尝试并行化以下构造:

for (r = 0; r <= (int)(N/2); r++)
{
    answer = ((answer % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;
}

使用简化似乎很自然,但在这种情况下不支持模运算符。

此外,我尝试使用私有变量,但竞争条件仍然存在:

#pragma omp parallel for private(temp)
for (r = 0; r <= (int)(N/2); r++)
{
    temp = answer;
answer = ((temp % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;
}

有没有办法让它发挥作用? 感谢。

2 个答案:

答案 0 :(得分:2)

您可以使用(x%a + y%a)%a = (x+y)%a的属性。然后

answer = ((answer % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;

相同
answer = (answer + 2 * solve(N, r) % MOD) % MOD;

总和,您可以显示这与

相同
Sum(answer + 2 * solve(N, r) % MOD)%MOD

因此,您需要做的就是这个

#pragma omp parallel for reduction(+:answer)
for (r = 0; r <= (int)(N/2); r++)
{
    answer += 2 * solve(N, r) % MOD
}
answer%=MOD;

这可能会溢出。在这种情况下,您可以像这样进行自定义缩减

#pragma omp parallel
{
    int answer_private = 0;
    #pragma omp for nowait
    for(int i=0; i<n; i++) {
        answer_private = ((answer_private % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;
    }
    #pragma omp critical
    {
        answer = (answer%MOD + answer_private%MOD)%MOD; 
    }
}

答案 1 :(得分:0)

由于您受到OpenMP 2.0可能的限制,您的方法是编写自定义缩减。基本方案是:

  • 在并行区域之前,为部分结果创建一个数组。它应该至少具有与并行区域中的线程一样多的元素;你可以使用omp_get_max_threads()函数作为上限。用零(用于求和的标识元素)初始化它。
  • 在并行区域内,使用omp_get_thread_num()函数获取并行区域内当前线程的编号,并将其用作上述数组的索引。在相应的数组元素中累积结果。
  • 在区域之后,使用串行循环来减少阵列中累积的部分结果。