我的问题如下。我必须编写一个计算斐波纳契数的一个非常大的元素的程序(它必须计算的最低值是pow(2,10)
成员,最大的是pow(2,20)
成员。为此,我使用GMP的mpz_t和它的计算功能。
我为此使用尾递归算法(稍后我必须让它并行运行)。问题是它会运行一段时间,然后突然:Segmentation fault (core dumped)
。
我告诉你我的代码,解释一下,所以你不必浪费时间搞清楚它并告诉你我要知道的事情。
int main(int argc, char** argv){
char result[1000000]; char *r; r = result;
long int n;
mpz_t num;
mpz_init(num);
double start_t, end_t, total_t;
start_t = omp_get_wtime();
for(int i = 0; i < 11; i++){
n = pow(2,i+10);
fibo(num,n);
char *d = mpz_get_str(NULL,10,num);
strcpy(r,d);
printf("The %ld. element of Fibonacci is: %s\n",n,result);
fflush(stdout);
memset(result, 0, sizeof result);
}
end_t = omp_get_wtime();
total_t = end_t - start_t;
printf("Time of running: %.6f\n",total_t);
return 0;
}
main()
函数基本上创建(并初始化)变量,设置时间测量,并在for循环中调用fibo()
函数,获取结果并打印它。一切都完成后,程序会写出运行时间并退出。
void fibo(mpz_t res, long int n){
if(n == 0){
mpz_set_str(res,"0",10);
return;
}else{
mpz_t temp1;
mpz_t temp2;
mpz_init_set_si(temp1,0);
mpz_init_set_si(temp2,1);
fiboTail(res,n,1,temp1,temp2);
mpz_clear(temp1);
mpz_clear(temp2);
}
}
fibo()
获得2个参数,第一个是mpz_t(对于那些不知道的人,这是一个指针,它将属于main()
中创建的那个,所以最终值将返回那里以供进一步使用),第二个值是我们需要计算的元素的数量。如果元素编号为0,我们只返回“0”,否则我们生成两个mpz_t变量,设置一个两个“0”,另一个设置为“1”并将它们与其他一些参数一起交给fiboTail()
void fiboTail(mpz_t res, long int n, long int m, mpz_t fibPrev, mpz_t fibCurrent){
if(n == m){
mpz_set(res,fibCurrent);
}else{
mpz_add(fibPrev,fibPrev,fibCurrent);
fiboTail(res,n, m + 1, fibCurrent, fibPrev);
}
}
所以这个基本上是核心。 m
计算我们已完成的添加次数,我们所处的元素,n
是我们需要的元素数量,fibCurrent
和fibPrev
是当前和之前的斐波那契分别是数字。
对于这个愚蠢的解释,我很抱歉,如果没有我试图解释,我认为大多数人都知道这一点。
所以,这个程序非常快。问题(Segmentation fault
)在计算第131072个元素时发生(有时在较小的元素上,它的......随机(?))。然后程序停止大约相同数量的加法/ m
值(并不总是在同一个值上,但接近那里),并显示前面提到的错误消息。我使用gcc
进行编译(实际上使用Makefile),因此我添加了-g
开关并使用gdb
来获取更多信息。这是我发现的:
我在gdb
中运行了该程序,并使用生成this的backtrace
。
Here是在帧#0-5上使用info frame
的详细堆栈信息。错误发生在mpz_add调用,但我不知道为什么。
如果您需要更多信息,我可以给他们,但是现在我不知道还有什么用处。
很抱歉这篇长篇文章,请提前感谢您的答案!
修改
由于mpz_add
似乎已经死亡,我得到了电话的信息,你可以看到它:i.imgur.com/XOpTve1.png(对不起,不能发布超过2个链接:/)
答案 0 :(得分:0)
不确定这是否有帮助,但这是用于查找fibonacci(n)的Lucas序列方法,这种方法很快并且可用于确认您的结果(例如结果的大小可能太大)。它类似于以矩阵形式实现fibnoacci(n)并使用重复平方将矩阵提升到n次幂,其中fib(n)= M ^ nx fib(0),其中M是2乘2矩阵,和fib()是一个2元素向量。 Lucas序列函数需要运行1 + log2(n)个循环,因此对于n = 2 ^ 20,它将需要21个循环。
uint64_t fibl(uint64_t n) {
uint64_t a, b, p, q, qq, aq;
a = q = 1;
b = p = 0;
while(1) {
if(n & 1) {
aq = a*q;
a = b*q + aq + a*p;
b = b*p + aq;
}
n >>= 1;
if(n == 0)
break;
qq = q*q;
q = 2*p*q + qq;
p = p*p + qq;
}
return b;
}
答案 1 :(得分:0)
尝试这样做:不是反复进行可能未优化的尾调用,而是迭代计算值或使用memoization。该程序可能在某处内存不足。