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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何为Fibonacci算法设计并行代码,但没有openmp任务?相关的知识,希望对你有一定的参考价值。

我想编写一个c ++代码,用于并行计算Fibonacci数,并使用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)

有人帮我这样做吗?

答案

这种方式是“酷”并且并行工作。请注意,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}

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

另一答案

下面是一个替代的并行解决方案,它使用黄金比率直接计算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
", i);
  for(int i=0; i<n; i++) printf("F%d: %" PRId64 " %" PRId64 "
", i, f1[i], f2[i]);      
}
另一答案

当我找到n个Fibonacci数的并行化时,我的一个朋友做了一个很酷的技巧。 我们都知道使用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的斐波纳契数。 类似地,第三个线程将首先使用矩阵指数查找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) 希望有所帮助!

以上是关于如何为Fibonacci算法设计并行代码,但没有openmp任务?的主要内容,如果未能解决你的问题,请参考以下文章

Fibonacci 数列第 N项 O(logN)算法

哈希表的插入复杂度如何为 O(1)

如何为没有附加外部通信方法的帐户创建密码重设系统?

uva10229-模Fibonacci

c语言经典算法---计算Fibonacci数列

如何为所有 SpecFlow 功能重新生成设计器代码