使用两个线程计算斐波那契序列
Calculate the Fibonacci sequence using two threads.
我有这个代码:
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { }
int Fibonacci(int nNumber) {
if (nNumber == 0)
return 0;
if (nNumber == 1)
return 1;
return Fibonacci(nNumber-1) + Fibonacci(nNumber-2);
}
void __fastcall TForm1::Button1Click(TObject *Sender) {
int k=0;
int val;
k = StrToInt(Edit1->Text);
for (int i=0; i < k; i++) {
val = Fibonacci(i);
Form1->ListBox1->Items->Add("F"+IntToStr(i)+"-->"+IntToStr(val));
}
}
我如何制作两个线程,分别计算和打印斐波那契序列的偶数和奇数索引数?
这是用于Builder 6中的练习。
您可以使用只使用偶数或奇数元素的斐波那契数公式。开发这个公式:
f(n) = f(n-1) + f(n-2) [1]
f(n-1) = f(n-2) + f(n-3) [2]
f(n-2) = f(n-3) + f(n-4) [3]
Combining [1] and [2]:
f(n) = 2 * f(n-2) + f(n-3) [4]
Rearranging [3]:
f(n-3) = f(n-2) - f(n-4) [5]
Combining [4] and [5]:
f(n) = 3 * f(n-2) - f(n-4) [6]
现在,每个线程都可以使用[6]计算偶数或奇数的斐波那契数,而无需等待其他线程的结果。
int Fibonacci(int nNumber) {
switch (nNumber)
{
case 0: return 0;
case 1: return 1;
case 2: return 1;
case 3: return 2;
default: return 3 * Fibonacci(nNumber-2) - Fibonacci(nNumber-4);
}
}
然而,这可能会破坏你的练习,使事情比预期的要简单得多。
有很多方法可以实现这一点。阿纳托利格的回答很好;这确实是解决这个问题的理想方法。
然而,就计算效率而言,计算斐波那契序列的方式存在一个大问题
注意:您可以在这里更改几乎所有的算法,使其只计算偶数或赔率。这些只是计算斐波那契数的更好方法。
你目前计算数字的方法不是很有效。使用当前算法计算仅一个数字的算法的时间复杂度已经是O(2^n),甚至不包括循环中的重复调用。一个计算斐波那契数的小程序不需要占用整个cpu一分钟来计算前100个数。
一个更好的递归算法如下(来自本页):
unsigned long fib(unsigned int n) {
return n == 0 ? 0 : fib2(n, 0, 1);
}
unsigned long fib2(unsigned int n, unsigned long p0, unsigned long p1) {
return n == 1 ? p1 : fib2(n - 1, p1, p0 + p1);
}
我们现在可以只在O(n)中计算fib(n)
的值,而不是在O(2^n)中。
这是另一个稍微高效的O(n)算法:
unsigned long fib(unsigned int n) {
unsigned long a=0,b=1;
for(unsigned long i = 0; i<n; i++)
a=(b+=a)-a; //there are a number of other variations on this statement,
//but that's not the point.
return a;
}
然而,在你的上下文中,如果你用它作为函数,它仍然有另一个问题,那就是它是画家的Schlemiel算法。这不好。由于它必须计算所有的数字,每次,你取每个数字的O(n),然后称它n次,总时间复杂度为O(n^2)。这仍然比你以前的O(2^n)要好得多,但仍然不好。
我们可以做得更好。
#INCLUDE <cmath>
#DEFINE (phi) (1.618033988749894848204586834365638117720309179805762862135448L)
#DEFINE (phiC) (–0.618033988749894848204586834365638117720309179805762862135448L)
#DEFINE (root5) (2.236067977499789696409173668731276235440618359611525724270897L)
//using long doubles to minimize the truncation errors,
//as fibonacci numbers can get extremely large
unsigned long fib(unsigned int n) {
return lrint(((pow(phi,n)-pow(phiC,n))/root5);
}
这一个使用Binet的公式直接计算结果,而不是按顺序计算,因此这一个特别容易从多个线程运行。
假设目标机器可以计算O(1)中的长双指数,那么输出所有斐波那契数的算法仅为O(n)。然而,许多体系结构都不能,所以你很可能最终得到O(n)表示函数,O(n^2)表示整个程序。
我们可以做得更好。
#INCLUDE <iterator>
class FibIterator: public std::Iterator<const unsigned long>{
unsigned long a=0,b=1;
public:
std::Iterator& operator++() {
unsigned long c = b;
b+=a;
a=c;
return(*this);
}
std::Iterator& operator--() {
unsigned long c = a;
a=b-a;
b=c;
return(*this);
}
const unsigned long& operator*(){
return a;
}
}
(可能不能100%工作,我已经好几年没有一次性编码这么多c++了)
由于您是一个接一个地计算它们,因此没有必要每次都重新计算所有内容。当你知道前两个斐波那契数时,计算下一个数只有O(1)。这段代码实际上是针对Iterator
类型的,它将迭代斐波那契数序列。这也可以作为一个简单的函数来实现,但这种方式更方便,因为您可以使用它只需一个调用来填充整个列表。
如果你只是把它作为for循环的一部分,你可以只在O(n)中计算出你想要的所有数字。
- 我可以计算多线程数的平均值吗?
- 用于在C++中计算用户数据的线程
- 在具有许多内核的计算机上,使用 Boost ASIO 只能使用 1 个线程
- 错误 C2064:term 的计算结果不是采用 1 个参数的函数 - 关于线程的一些东西
- 提升线程:术语的计算结果不为 0 个参数
- 从多个线程组随机计算着着色器写入RWStructuredBuffer
- 多线程蒙特卡罗计算中没有加速
- 使用C 中的线程并行计算
- 在 C++11 中计算字母和单词的双字母组合的 std::线程向量的问题
- 多线程计算均值和std并不能提高效率
- 我遇到了一个关于多线程的小问题.需要多线程来计算 Pi 和方差
- 多个线程创建5个线程来计算质数
- C++STL多线程,并行运行计算
- 线程:如何在C或C++中精确计算算法的执行时间(函数的持续时间)
- qt多线程:计算一个积分
- 计算创建 n 个线程所花费的时间
- 使用C++中的线程来报告计算进度
- 使用多线程计算质数
- 计算线程运行的次数
- 正在计算线程内的时间