如何为Fibonacci算法设计并行代码,但没有openmp任务?

时间:2017-12-06 20:18:45

标签: parallel-processing openmp fibonacci

我想编写一个用于并行计算Fibonacci数的c ++代码,并使用OpenMP工具。我知道,使用#pragma omp task,代码将是:

int fib(int n) {
int i, j;
if (n<2)
    return n;
else {
    #pragma omp task shared(i)
    i=fib(n-1);
    #pragma omp task shared(j)
    j=fib(n-2);
    #pragma omp taskwait
    return i+j;
    }
}

以这种方式计算并不酷,因为每个线程都在等待其子线程完成其工作,因此整个过程仍然是顺序的!

我想用以下等式编写并行代码:

F(n + k)= F(n + 1)* F(k)+ F(n)* F(k - 1)

有人会帮我这么做吗?

3 个答案:

答案 0 :(得分:2)

这种方式是&#34;很酷&#34;并行工作。请注意,taskwait允许线程执行其他任务,例如由它自己的子任务创建的任务。只是为了说明可能的执行计划:

* creating a task , # actually waiting for all child tasks
           ------- time --->
Thread 1   {fib(4): **b      {fib(2): ** {fib(1): ret 1}   # ret 1+0}         # ret 2+1
Thread 2            {fib(3): ** {fib(1): ret 1}                     # ret 1+1}
Thread 3             {fib(2): ** {fib(0): ret 0} ret 1+0}
Thread 4                      {fib(1): ret 1}{fib(0): ret 0}

当然,与迭代计算相比,代码仍然非常低效。此外,在使用递归算法任务的实际代码中,应在某个递归深度之后停止创建新任务以管理任务创建开销。

答案 1 :(得分:0)

下面是一个替代并行解决方案,它使用黄金比率直接计算fib(n)fib(n+1),然后为每个线程顺序计算序列的其余部分。我从rosettacode得到了直接解决方案。

问题是直接计算溢出n>72所以这个方法几乎肯定比按顺序计算前71个数字要慢,而且在任何情况下,n>92都会溢出64位整数。

#include <math.h>
#include <stdio.h>
#include <inttypes.h>
#include <omp.h>

uint64_t fib(unsigned m) { // Direct Calculation, correct for abs(m) <= 71
  double sqrt5r =  1.0 / sqrt(5.0);      
  double golden = (1.0 + sqrt(5.0))/2.0;
  return rint(pow(golden, m)*sqrt5r);
}

void fib_sequence(unsigned n, uint64_t *f) {
  #pragma omp parallel
  {
    size_t t  = omp_get_thread_num();
    size_t nt = omp_get_num_threads();
    int x0 = (t+0)*n/nt;
    int x1 = (t+1)*n/nt;
    f[x0 + 0] = fib(x0 + 0);
    f[x0 + 1] = fib(x0 + 1);
    for(int i=x0+2; i<x1; i++) {
      f[i] = f[i-2] + f[i-1];
    }
  }
}

int main(void) {
  int n = 71;
  uint64_t f1[n], f2[n];
  for(int i=0; i<n; i++) f1[i] = fib(i);
  fib_sequence(n, f2);
  for(int i=0; i<n; i++) if(f1[i] != f2[i]) printf("%d\n", i);
  for(int i=0; i<n; i++) printf("F%d: %" PRId64 " %" PRId64 "\n", i, f1[i], f2[i]);      
}

答案 2 :(得分:0)

我的一个朋友在找到n个斐波纳契数的并行化时做了一个很酷的技巧。
我们都知道使用matrix exponentation可以在log(k)时间找到kth fibonacci数。
斐波纳契(j)也只取决于斐波纳契(j - 1)和斐波那契(j - 2)
假设你有四个线程,那么第一个线程将被赋予迭代地找到0到(n / 4)-1个斐波纳契数的任务。 现在第二个线程必须找到从n / 4到2n / 4 - 1的斐波纳契数,但为此它需要fibo(n / 4 - 1)。那么现在的诀窍就是这个线程会在O(log(n))时间内使用矩阵指数来计算fibo(n / 4)和fibo(n / 4 + 1)(没有多少时间正确且聪明,因为我们不等待第一个线程的最终结果)。现在,一旦第二个线程获得fibo(n / 4)和fibo(n / 4 + 1),它将与其他线程并行查找从n / 4到2n / 4 - 1的fibonacci数字。
类似地,第三个线程将首先使用矩阵指数查找fibo(2n / 4)和fibo(2n / 4 + 1),它将与其他线程并行查找从2n / 4到3n / 4 - 1的斐波那契数。
最后的第四个线程也会做同样的事情。
现在,如果你要求性能,可用的p theads中的每个线程将花费最多2log(n)的时间并进行n / p迭代,这将花费O(n / p)时间。所以每个线程最多只能完成O(n / p + log(n))的工作,加速将是pn / n + plog(n)
希望有所帮助!